문제가 무슨 말인지를 몰라서 푸는 데 시간이 걸리는 문제이다.
힌트는 주어져 있지만...
약간, DFS와 Disjoint Set이 필요한 이유를 찾아보기는 힘들지만,
전에 이야기하듯이, find와 merge를 이용하면 쉬운 문제이다.
즉, find에서는 부모 배열에서 같은 값이 있으면 그 값을 리턴하면 되지만, 없으면
자식이 있을 때까지 찾는 것이다.
즉, 만약 자식을 찾으면 merge에서 x와 y가 같으면 끝이지만, 아니라면 SAFE ZONE이 될 수 없다는 의미인 거 같다.
x = (i * m + j)로 주로 맡는다.
그럼 y는?
y는 상하좌우 역할을 맡게 하면 된다.
여러 경우로 나눈 거 보면 얼핏 DFS와 유사해보인다.
DFS는 Depth기준으로 하여 경우를 찾는 것을 말한다.
긴 if문을 단순하게 만들 수 있다는 장점이 있기도 해서 유용한 알고리즘이다.
하지만, disjoint set으로 이용해야 하므로,
c++에서 제공하는 set으로 이용한다.
find(i * m + j)를 불러와서 찾은 자식들의 값을 set에 저장하면 된다.
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
int n, m;
char map[1001][1001];
int parent[1000001];
int find(int x) {
if (parent[x] == x) return x;
return parent[x] = find(parent[x]);
}
void merge(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return;
parent[x] = y;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> map[i][j];
}
}
for (int i = 0; i < n * m; i++) {
parent[i] = i;
}
// 상하좌우
// 방향이 상이면 i*m+j와 (i-1)*m+j를 합친다.
// 방향이 하이면 i*m+j와 (i+1)*m+j를 합친다.
// 방향이 좌이면 i*m+j와 i*m+j-1를 합친다.
// 방향이 우이면 i*m+j와 i*m+j+1를 합친다.
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (map[i][j] == 'U') {
merge(i * m + j, (i - 1) * m + j);
} else if (map[i][j] == 'D') {
merge(i * m + j, (i + 1) * m + j);
} else if (map[i][j] == 'L') {
merge(i * m + j, i * m + j - 1);
} else if (map[i][j] == 'R') {
merge(i * m + j, i * m + j + 1);
}
}
}
set<int> s;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
s.insert(find(i * m + j));
}
}
cout << s.size() << endl;
return 0;
}
시간 복잡도: O(NM)
소스는 참고용으로 쓰기를...
'백준 온라인 저지 싹쓸이' 카테고리의 다른 글
[BOJ16946] 벽 부수고 이동하기 4 (1) | 2022.09.25 |
---|---|
[BOJ4386] 별자리 만들기 (1) | 2022.09.24 |
[BOJ2887] 행성 터널 (0) | 2022.09.24 |
[BOJ 11257] IT 시험 (0) | 2022.09.23 |
[BOJ2473] 세 용액 (1) | 2022.09.22 |