DFS와 Union Find를 활용하는 문제. 각 노드가 진행하는 방향도 단방향이고, 지도 밖으로 나가는 방향의 입력도 주어지지 않는다. N과 M의 크기도 최대 1,000이라서 최대 노드의 수 또한 1,000,000이다. 조건이 꽤나 친절하다.
각 노드를 탐색하면서 방문 체크를 해가며 DFS를 돌리게 되면 사이클이든 아니든 끝에 도달하게 되고, 그 경로 상에 있는 모든 노드는 같은 집합으로 처리해 준다. 집합 내에서는 어디서 출발하든 공통적으로 도달하게 되는 한 노드가 있기 때문에, 한 집합에는 하나의 SAFE ZONE만 두면 된다.
한 노드에 대해 DFS를 끝냈다면 다음 노드를 탐색하는데, 이 때 방문한 노드라면 이전 탐색 과정에서 어떤 집합에 속하게 된 것이므로 DFS를 추가적으로 할 필요가 없다. DFS를 할 때 주의할 점은, 구현하기 나름이겠지만 탐색 중에 다음에 방문하려는 노드가 이미 방문 상태일 경우, 해당 노드의 집합과 union 처리를 해주어야 한다는 것이다. 사이클을 형성하는 집합이 있고, 그 사이클에 단방향으로 향하는 노드 경로를 생각해 보면 된다.
모든 DFS를 끝내고 나면, find로 각각의 root를 찾아내서 총 몇 개의 집합이 형성되었는지를 확인해서 출력하면 된다. 전체 시간 복잡도는 O(N*M)으로 충분하다.
#include <iostream>
#include <unordered_map>
using namespace std;
int root[1000000];
char matrix[1000][1000];
bool isVisited[1000][1000];
int find(int x) {
if(root[x] == x) {
return x;
} else {
root[x] = find(root[x]);
return root[x];
}
}
void makeUnion(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if(rootX<rootY) {
root[y] = rootX;
} else {
root[x] = rootY;
}
}
int main() {
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int n, m;
cin >> n >> m;
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
cin >> matrix[i][j];
root[i*1000 + j] = i*1000 + j;
}
}
int curY, curX, curInd;
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
curY = i;
curX = j;
curInd = i*1000 + j;
while(!isVisited[curY][curX]) {
isVisited[curY][curX] = true;
switch(matrix[curY][curX]) {
case 'R': {
curX++;
break;
}
case 'D': {
curY++;
break;
}
case 'L': {
curX--;
break;
}
case 'U': {
curY--;
}
}
makeUnion(curInd, curY * 1000 + curX);
}
}
}
unordered_map<int, int> um;
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
um[find(i*1000+j)]++;
}
}
cout << um.size();
}
'Dev > BOJ' 카테고리의 다른 글
[백준 17404] RGB거리 2 (0) | 2024.09.11 |
---|---|
[백준 16946] 벽 부수고 이동하기 4 (2) | 2024.09.10 |
[백준 11401] 이항 계수 3 (1) | 2024.09.07 |
[백준 10775] 공항 (3) | 2024.09.06 |
[백준 9527] 1의 개수 세기 (0) | 2024.09.05 |