[백준 11559 : C++] Puyo Puyo / BFS, DFS
문제
풀이
( 문제를 이해하는데 30분 정도 걸렸고, 푸는데 2시간 정도 걸렸다. )
BFS로 풀었고 알고리즘은 아래처럼 적용했다.
- BFS를 통해 맵의 각 영역을 별도의 맵에 저장한다. (같은 색이라도 다른 영역에 있다면 구분한다.)
- 4개 이상의 뿌요를 가지는 영역이 없다면 종료한다.
- 해당 영역이 4개 이상의 뿌요를 가진다면 터뜨린다.
- 맵을 refresh한다. (중력에 따라 뿌요를 아래로 내릴 수 있다면 내린다.)
- 연쇄 + 1
- 1번부터 반복 (2번을 만날때 까지)
코드
C++ 언어를 이용하여 코드로 살펴보자.
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
constexpr short ROW = 12;
constexpr short COL = 6;
constexpr short directionX[] = { 0, 0, -1, 1 };
constexpr short directionY[] = { -1, 1, 0, 0 };
char map[ROW][COL + 1];
int chain;
int labelingMap[ROW][COL] = { 0, }; // 영역을 저장할 별도의 맵
bool visited[ROW][COL] = { 0, };
int labelCount[12 * 6 + 1] = { 0, }; // 영역은 1번부터 시작하기 때문에 +1
struct Point {
short x;
short y;
Point() {}
Point(int _x, int _y) : x(_x), y(_y) {}
};
bool rangeCheck(int x, int y) {
return (0 <= x && x < COL && 0 <= y && y < ROW);
}
// 1번의 BFS 탐색을 이용해 영역을 나눈다.
// 만약 같은 색이라도 다른 영역에 있다면 서로를 구분한다.
void bfs(int x, int y, int label) {
char color = map[y][x];
queue<Point> q;
q.push({ x, y });
visited[y][x] = true;
labelingMap[y][x] = label;
labelCount[label]++;
while (!q.empty()) {
int x = q.front().x;
int y = q.front().y;
q.pop();
for (int i = 0; i < 4; i++) {
int nextX = x + directionX[i];
int nextY = y + directionY[i];
if (rangeCheck(nextX, nextY)) {
if (!visited[nextY][nextX] && map[nextY][nextX] == color) {
visited[nextY][nextX] = true;
labelingMap[nextY][nextX] = label;
labelCount[label]++;
q.push(Point{ nextX, nextY });
}
}
}
}
}
int setLabelingMap() {
int label = 1;
for (int y = 0; y < ROW; y++) {
for (int x = 0; x < COL; x++) {
if (!visited[y][x] && map[y][x] != '.') {
bfs(x, y, label++);
}
}
}
return label;
}
void gravityPuyo() {
for (int i = 0; i < COL; i++) {
int target = 1, base = 0; // 목표지점, 현재 지점
while (base + target < ROW) {
if (map[base][i] != '.') // 공백 지점 탐색
base++;
else if (map[target + base][i] == '.') // 바꿔야할 지점 탐색
target++;
else { // 현재 지점이 공백 이면서 바꿔야 할 지점이 Puyo인 경우
swap(map[base][i], map[base + target][i]);
base++;
target = 1;
}
}
}
}
void burstPuyo(int label) { // 현재 맵에서 4개 이상의 뿌요를 터뜨린다.
for (int i = 1; i <= label; i++) {
if (labelCount[i] >= 4) {
for (int y = 0; y < ROW; y++) {
for (int x = 0; x < COL; x++) {
if (labelingMap[y][x] == i)
map[y][x] = '.';
}
}
}
}
}
bool hasBurstPuyo(int label) { // 현재 맵에서 터뜨릴 수 있는 뿌요가 있는지 확인한다.
for (int i = 1; i <= label; i++)
if (labelCount[i] >= 4) return true;
return false;
}
int main() {
for (int i = ROW - 1; i >= 0; i--)
cin >> map[i];
while (true) {
// visited, labelingMap, labelCount 3개의 변수를 초기화한다.
memset(visited, false, sizeof(visited));
memset(labelingMap, 0, sizeof(labelingMap));
memset(labelCount, 0, sizeof(labelCount));
int label = setLabelingMap();
if (!hasBurstPuyo(label)) break; // 터뜨릴 수 있는 뿌요가 없다면 루프 종료
burstPuyo(label); // 4개 이상의 뿌요를 터뜨린다.
gravityPuyo(); // map을 refresh한다. (중력에 따라 뿌요를 아래로 내릴 수 있다면 내린다.)
chain += 1; // 연쇄 + 1
}
cout << chain << "\n";
return 0;
}
'Algorithm > Baekjoon' 카테고리의 다른 글
[백준 2206 : JAVA] 벽 부수고 이동하기 / BFS (0) | 2020.09.08 |
---|---|
[백준 9370 : JAVA] 미확인 도착지 / 다익스트라 (0) | 2020.08.28 |
[백준 11057 : C++] 오르막 수 / DP (0) | 2019.10.24 |
[백준 2661 : C++] 좋은수열 / 백트래킹 (0) | 2019.09.28 |
[백준 2749 : C++] 피보나치 수 3 (0) | 2019.08.29 |
댓글
이 글 공유하기
다른 글
-
[백준 9370 : JAVA] 미확인 도착지 / 다익스트라
[백준 9370 : JAVA] 미확인 도착지 / 다익스트라
2020.08.28 -
[백준 11057 : C++] 오르막 수 / DP
[백준 11057 : C++] 오르막 수 / DP
2019.10.24 -
[백준 2661 : C++] 좋은수열 / 백트래킹
[백준 2661 : C++] 좋은수열 / 백트래킹
2019.09.28 -
[백준 2749 : C++] 피보나치 수 3
[백준 2749 : C++] 피보나치 수 3
2019.08.29