Disjoint-Set (서로수 집합) 이라고도 불리는 유니온 파인드는 여러 집합이 주어지면 각 집합의 루트 노드가 무엇인지,
또는 Union(합집합) 연산을 손쉽게 하기 위한 일종의 자료구조이다.
큰 틀로는 집합의 부모 노드를 찾는 find 함수, 각 집합을 병합하는 union 함수를 만들어주면 된다.
int find(int x) {
if (parent[x] < 0) return x;
parent[x] = find(parent[x]);
return parent[x];
}
find 함수부터 살펴보면 parent배열의 초기값은 -1로 설정해둔다(이후에 집합의 크기를 알기 쉽게 하기 위해)
만약 parent [x]가 0보다 작다는 소리는 그 노드가 루트 노드임을 알 수 있다.
그대로 x를 반환하면 된다.
만약 루트 노드가 아닐경우 재귀적으로 그 노드의 부모 노드를 호출하여 parent [x]에 담는다. 이후 모든 호출이 끝나면
parent [x]를 리턴해주면 된다.
void merge(int x, int y) {
x = find(x);
y = find(y);
if (x != y) parent[y] = x;
}
merge는 union연산이다. C언어에서는 union이 이미 사용되고 있기 때문에 union함수명을 사용할 수 없다.
두 집합이 주어지면 그 두 집합의 부모 노드를 찾아서 그 노드가 서로 같지 않다면(같은 집합이 아니라면)
한 노드에 다른 노드를 붙여주기만 하면 된다.
백준에서 연습해볼 만한 문제로는
1717번: 집합의 표현
첫째 줄에 n(1≤n≤1,000,000), m(1≤m≤100,000)이 주어진다. m은 입력으로 주어지는 연산의 개수이다. 다음 m개의 줄에는 각각의 연산이 주어진다. 합집합은 0 a b의 형태로 입력이 주어진다. 이는 a가 ��
www.acmicpc.net
집합의 표현이 있다. 문제를 읽어보면 0 ~ n까지 집합을 병합하고
그 집합이 같으면 YES 아니면 NO를 출력해주면 된다.
#include <iostream>
#include <vector>
using namespace std;
vector<int> parent;
int n, m, a, b, input;
int find(int x) {
if (parent[x] < 0) return x;
parent[x] = find(parent[x]);
return parent[x];
}
void merge(int x, int y) {
x = find(x);
y = find(y);
if (x != y) parent[y] = x;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m;
parent.resize(n + 1, -1);
while (m--) {
cin >> input >> a >> b;
if (input == 0) merge(a, b);
else if (input == 1) {
if (find(a) == find(b)) cout << "YES" << '\n';
else cout << "NO" << '\n';
}
}
return 0;
}
유니온 파인드는 이후 다른 알고리즘에 융합되어 사용된다고 한다.
'Algorithm' 카테고리의 다른 글
플로이드 - 와샬 알고리즘 (0) | 2020.10.19 |
---|---|
벨만 - 포드 알고리즘 (0) | 2020.10.18 |
순열과 조합 (0) | 2020.10.02 |
다익스트라 알고리즘 (0) | 2020.09.24 |
약수 구하기 최적화 (0) | 2020.09.07 |