뭔지 모르게 서핑하다가 union-find문제를 발견하였는데 아직 한번도 풀어본 적이 없어서 경험삼아 한번 풀어보았다. 생각보다 개념은 어렵지 않다. 두 개의 다른 집단이 인접하였고 또 서로 index가 다르다면 합치면 된다. 종료조건은 집단이 하나만 남았을 때로 하면 된다. (www.youtube.com/watch?v=_N0hk13QM6w)
#include<iostream>
#include<queue>
using namespace std;
int N, K, civ[2002][2002], year;
queue<pair<int, int>> q, qq;
int p[1000002], Rank[1000002];
int root(int x) {
if (x == p[x]) return x; // x라는 값이 해당 부모의 값과 동일하다면 x를 return
return root(p[x]); // 다르면 부모를 찾는다. 재귀적으로
}
bool unions(int x, int y) {
x = root(x);
y = root(y);
if (x == y) return true;
else {
if (Rank[x] > Rank[y]) p[y] = x; //y가 x의 밑으로 들어가니까
else if (Rank[x] < Rank[y]) p[x] = y;
else { //rank 2개가 같다는 거니까 x밑으로 넣어주자(x밑으로 넣어줘도 되고 y밑으로 넣어줘도 되고)
Rank[x]++;
p[y] = x;
}
return false;
}
}
int dx[] = { 1,0,0,-1 };
int dy[] = { 0,1,-1,0 };
void bfs() {
while (1) {
while (!q.empty()) { //합칠 수 있는 문명을 다 합쳐준다.
int cx = q.front().first;
int cy = q.front().second;
qq.push(q.front());
q.pop();
for (int i = 0; i < 4; i++) {
int nx = cx + dx[i];
int ny = cy + dy[i];
if (nx <= 0 || nx > N || ny <= 0 || ny > N) continue;
if (civ[nx][ny] != 0 && civ[nx][ny] != civ[cx][cy]) {
if (!unions(civ[nx][ny], civ[cx][cy])) {
K--;
}
}
}
}
if (K == 1) {
cout << year;
return;
}
while (!qq.empty()) { // 문명을 전파시킨다.
int cx = qq.front().first;
int cy = qq.front().second;
qq.pop();
for (int i = 0; i < 4; i++) {
int nx = cx + dx[i];
int ny = cy + dy[i];
if (nx <= 0 || nx > N || ny <= 0 || ny > N) continue;
if (civ[nx][ny] == 0) {
civ[nx][ny] = civ[cx][cy];
q.push({ nx,ny });
}
else if (civ[nx][ny] != civ[cx][cy]) {
if (!unions(civ[nx][ny], civ[cx][cy])) {
K--;
}
}
}
}
year++;
}
}
int main() {
cin >> N >> K;
for (int i = 1; i <= K; i++) {
int x, y;
cin >> x >> y;
p[i] = i;
civ[x][y] = i;
q.push({ x,y });
}
bfs();
return 0;
}
'Programming > BOJ' 카테고리의 다른 글
[백준/C++] 1874번: 스택수열 (0) | 2020.09.15 |
---|---|
[백준/C++] 1181번: 단어정렬 (0) | 2020.09.14 |
[백준/C++] 13460번: 구슬 탈출2 (어려워) (0) | 2020.09.09 |
[백준/C++] 14923번: 미로탈출 (0) | 2020.09.08 |
[백준/C++] 14502번: 연구소 (0) | 2020.09.07 |