문제
크기가 N×N인 그리드의 각 칸에 RGB 중 하나를 칠한 그림이 있다.
같은 색으로 이루어져 있는 구역으로 몇 개 나뉘어져 있다.
같은 색상이 상하좌우로 인접해 있으면 같은 구역에 속한다.
적록색약인 사람은 R과 G를 구별하지 못 한다.
그리드가 주어졌을 때, 적록색약이 아닌 사람이 봤을 때의 구역의 개수와 적록색약인 사람이 봤을 때의 구역수를 세어보자.
조건
1 ≤ N ≤ 100
풀이
이 문제는 2667번의 응용버전이다.
그리드에서 RGB 문자가 있는 한 칸을 기준으로 너비우선탐색을 하는데, 한 번 방문한 칸에는 숫자 등을 채워 넣는다.
그리고 더 이상 RGB 문자가 등장하지 않을 때까지 이를 반복한 뒤, 몇 번을 반복했는지만 출력하면 그게 구역의 수이다.
이 문제에서는 이를 두 번 반복해야 하는데, 왜냐하면 R과 G를 같다고 가정하는 적록색약의 경우를 별도로 고려해줘야 하기 때문이다.
따라서, 각 탐색을 시작할 때, 그리드의 정보를 다른 임시 그리드에 복사하여 그 임시 그리드를 가지고 너비우선탐색을 반복해야 한다.
아래는 프로그램의 동작과정이다.
1. 우선, grid의 정보를 입력받아 저장한다.
2. grid를 _grid에 복사한다.
3. 구역의 수를 나타낼 변수 count를 선언하고 초기값을 0으로 둔다.
4. 그리고 아래(5 ~ 8)를 반복한다.
5. _grid에서 RGB 문자가 있는 칸을 찾고, 그 위치를 큐 BFS에 담은 뒤 지정한 레이블로 이동한다.
- 이 때 그 칸의 색을 color 변수에 저장한다.
6. 만약, RGB 문자가 있는 칸을 찾지 못 했다면 반복을 탈출한다.
7. 너비우선탐색을 진행한다. 인접한 칸이 color와 같은 색이라면 BFS에 넣는다.
8. 방문한 칸에는 count의 값을 저장한다.
9. count의 값에 1을 더한다.
10. 위의 과정 중 2 ~ 9를 한 번 더 반복하는데, 이 때는 2의 과정에서 R과 G는 한 문자로 통일한다.
📕 코드보기(틀린 코드)
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
#define EL "\n"
int getCount(const char* source, int N, bool type) {
char* grid = new char[N * N];
memcpy(grid, source, sizeof(char) * (N * N));
if (type)
for (int i = 0; i < N * N; i++)
if (grid[i] == 'R')
grid[i] = 'G';
int count = 0;
int UDLR[4][2]{ {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
while (true) {
queue<pair<int, int>> colors;
for (int r = 0; r < N; r++)
for (int c = 0; c < N; c++)
if (grid[r * N + c] != 0) {
colors.push(make_pair(r, c));
goto OUT;
}
break;
OUT:;
while (colors.size()) {
auto [r, c] = colors.front();
if (grid[r * N + c] == 0) {
colors.pop();
continue;
}
for (auto d : UDLR) {
int dr = r + d[0];
int dc = c + d[1];
if (dr < 0 || dr >= N)
continue;
if (dc < 0 || dc >= N)
continue;
if (grid[dr * N + dc] == 0)
continue;
if (grid[dr * N + dc] == grid[r * N + c])
colors.push(make_pair(dr, dc));
}
grid[r * N + c] = 0;
colors.pop();
}
count++;
}
delete[] grid;
return count;
}
int main() {
cin.tie(NULL);
ios::sync_with_stdio(false);
int N;
cin >> N;
char* grid = new char[N * N];
for (int i = 0; i < N * N; i++)
cin >> grid[i];
cout << getCount(grid, N, false) << " " << getCount(grid, N, true) << EL;
delete[] grid;
return 0;
}
결과
메모리초과
분석
1. 큐에 너무 많은 요소가 들어감으로 인해 발생한 결과일 것이다.
2. 큐에 들어갈 정보를 더 줄이거나 다른 방법을 생각해야 한다.
3. 사실 사소한 문제가 있었다. 다녀간 칸에 몇 번 영역인지 수를 저장했는데, 이 수가 RGB 문자와 겹칠 수가 있다.
4. 다녀간 칸을 0으로 표시함으로써 이 문제를 해결했다.
답안
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
#define EL "\n"
int getCount(const char* source, int N, bool type) {
char* grid = new char[N * N];
memcpy(grid, source, sizeof(char) * (N * N));
if (type)
for (int i = 0; i < N * N; i++)
if (grid[i] == 'R')
grid[i] = 'G';
int count = 0;
int UDLR[4][2]{ {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
while (true) {
queue<pair<int, int>> colors;
for (int r = 0; r < N; r++)
for (int c = 0; c < N; c++)
if (grid[r * N + c] != 0) {
colors.push(make_pair(r, c));
goto OUT;
}
break;
OUT:;
while (colors.size()) {
auto [r, c] = colors.front();
if (grid[r * N + c] == 0) {
colors.pop();
continue;
}
for (auto d : UDLR) {
int dr = r + d[0];
int dc = c + d[1];
if (dr < 0 || dr >= N)
continue;
if (dc < 0 || dc >= N)
continue;
if (grid[dr * N + dc] == 0)
continue;
if (grid[dr * N + dc] == grid[r * N + c])
colors.push(make_pair(dr, dc));
}
grid[r * N + c] = 0;
colors.pop();
}
count++;
}
delete[] grid;
return count;
}
int main() {
cin.tie(NULL);
ios::sync_with_stdio(false);
int N;
cin >> N;
char* grid = new char[N * N];
for (int i = 0; i < N * N; i++)
cin >> grid[i];
cout << getCount(grid, N, false) << " " << getCount(grid, N, true) << EL;
delete[] grid;
return 0;
}
'프로그래밍 > PS' 카테고리의 다른 글
[C++] 백준 16236번: 아기 상어 (0) | 2020.11.01 |
---|---|
[C++] 백준 1107번: 리모컨 (0) | 2020.11.01 |
[C++] 백준 15686번: 치킨 배달 (0) | 2020.10.29 |
[C++] 백준 7569번: 토마토 (0) | 2020.10.28 |
[C++] 백준 17626번: Four Sqaures (0) | 2020.10.27 |