DFS(깊이 우선 탐색)을 활용하는 문제이다. 2D 맵을 쓰는것을 보고 이건 BFS인가 DFS인가 했는데 경로를 찾는게 아니라 일단 DFS로 생각했고, 그쪽 접근이 나쁘지 않았다. 이전에 MST 문제를 풀 때, 2D로 된 섬들이 있는 맵에서 MST를 찾는 문제가 있었다. 해당 문제에서는, 지도에 섬이 몇개 있는지 알아야 했고, 맵에 있는 각 섬 픽셀이 어느 섬에 속해있는지 찾아야 했다. 그 과정에서 DFS를 사용해 섬 그루핑을 했는데, 그것과 거의 동일하게 이번 문제 풀이가 진행된다.
문제 풀이의 흐름은 다음과 같다.
- 어떤 특정한 픽셀에서 시작한다.
- 그 픽셀에서 상하좌우 픽셀을 탐색한다.
- 넘어온 픽셀이 탐색되지 않은 픽셀이고, 넘어오기 전 픽셀 색과 같으면 탐색 배열에 현재 그룹의 인덱스를 적어둔다.
- 2번 반복
- 만약, 이미 탐색된 픽셀이거나 넘어오기 전 픽셀 색과 다르면 탐색을 중지한다.
어떤 픽셀에서 DFS 함수를 실행하면, 해당 픽셀에서 같은 색의 그룹을 찾을 수 있다. 해당 그룹은 탐색 배열에 인덱스들로 표시된다.
이제 매 픽셀마다 DFS함수를 실행하면 된다. 특정 그룹에서 처음으로 실행된 픽셀 탐색일때만 전체 DFS 탐색이 되고, 그 때 탐색 배열에 표시를 하게 되므로, 이미 그루핑이 된 픽셀은 DFS탐색이 되지 않는다. 탐색이 완료되어 새 그룹이 된 경우 true를 리턴해 그룹 인덱스를 1 더해준다.
이제 정상시야와 적록색약을 구분하면 되는데, 그냥 똑같은 로직에 똑같은 배열을 하나 더 만드는 것으로 해결했다. N*N 맵으로 탐색을 하게 되는데, N이 100으로 크지 않기때문에 똑같은 맵을 하나 더 만들어도 메모리가 초과되지 않을 것이다. 정상시야의 경우, 탐색할 때 계속 같은 색일 경우 탐색이 진행되었다. 적록색약일 경우, 해당 조건을 살짝 바꿔 R일때 R, G인 경우, G 일때 R, G인 경우, B 일때 B일 경우 탐색을 계속하도록 if 문만 바꿨다. 템플릿으로 만들어서 깔끔하게 할 수도 있을 것 같다.
코드는 다음과 같다.
#include <iostream>
#include <string.h>
char MAP[100][100];
int CW[100][100];
int NV[100][100];
int NVGroup = 0;
int CWGroup = 0;
int N;
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
int GroupNV(int y, int x, char color)
{
if (y<0 || x <0 || x > N-1 || y >N-1)
return 0;
if (NV[y][x] == -1)
{
if (MAP[y][x] == color)
{
NV[y][x] = NVGroup;
for (int i = 0; i < 4; i++)
GroupNV(y+dy[i], x+dx[i], color);
return 1;
}
return 0;
}
return 0;
}
void NormalVision()
{
for (int y = 0 ; y < N; y++)
{
for (int x = 0; x < N; x++)
{
int groupped = GroupNV(y, x, MAP[y][x]);
if (groupped)
NVGroup++;
}
}
}
int GroupCW(int y, int x, char color)
{
if (y<0 || x <0 || x > N-1 || y >N-1)
return 0;
if (CW[y][x] == -1)
{
if (MAP[y][x] == color || (MAP[y][x] == 'R' && color == 'G') || (MAP[y][x] == 'G' && color == 'R'))
{
CW[y][x] = CWGroup;
for (int i = 0; i < 4; i++)
GroupCW(y+dy[i], x+dx[i], color);
return 1;
}
return 0;
}
return 0;
}
void ColorWeakness()
{
for (int y = 0 ; y < N; y++)
{
for (int x = 0; x < N; x++)
{
int groupped = GroupCW(y, x, MAP[y][x]);
if (groupped)
CWGroup++;
}
}
}
int main()
{
std::cin >> N;
memset(CW, -1, sizeof(CW));
memset(NV, -1, sizeof(NV));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N ; j++)
{
std::cin >> MAP[i][j];
}
}
NormalVision();
ColorWeakness();
std::cout << NVGroup << " " << CWGroup ;
}
한줄만 다른 함수가 두개씩 있으니 좀 보기 그렇긴 하다. 이 문제는 거의 2D 맵 DFS의 스탠다드라고 할 수 있는것 같다.
페북이나 인스타를 들어가지 말아야겠다... 왜 거기는 다 잘난사람들이 있는거지... ㅏ하ㅏ하...
오늘도 평온한 하루가 되길. 슨민.
'짜잘한 기록' 카테고리의 다른 글
백준 3109 빵집 (0) | 2021.09.10 |
---|---|
백준 1167 트리의 지름 (0) | 2021.09.09 |
백준 1963 소수 경로 (0) | 2021.09.08 |
백준 2206 벽 부수고 이동하기 (0) | 2021.09.07 |
[나만 몰랐던 알고리즘] 2D 맵 BFS (0) | 2021.09.06 |