서로소 집합(Disjoint Set) : 공통 원소가 없는 두 집합
서로소 부분 집합들로 나누어진 원소들을 데이터를 처리하기 위한 자료구조이다.
union과 find 2개의 연사으로 조작할 수 있다.
트리 자료구조로 표현한다.
✔️union-find 방식
1. union(합집합)
1) A와 B의 부모노드 A', B'을 각각 찾는다.
2) A'를 B'의 부모 노드로 설정한다. (if. A' < B')
2. find(부모노드 찾기)
루트 노드 탐색
<1번째 소스 : 수정 전>
#include <iostream>
#include <vector>
using namespace std;
// 노드의 개수(v)와 간선(e)의 개수
// 노드의 개수는 최대 100000개라고 가정
int v, e;
int parent[100001];
// 특정 원소가 속한 집합을 찾기
int findParent(int x) {
if (parent[x] != x) {
return findParent(parent[x]);
}
return x;
}
// 두 원소가 속한 집합을 합치기
void unionParent(int x, int y) {
x = findParent(x);
y = findParent(y);
if (x < y) {
parent[y] = x;
}
else {
parent[x] = y;
}
}
int main(void) {
cin >> v >> e;
// 부모테이블 상에서, 부모를 자기 자신으로 초기화
for (int i = 1; i <= v; i++) {
parent[i] = i;
}
// union 연산을 각각 수행
for (int i = 0; i < e; i++) {
int a, b;
cin >> a >> b;
unionParent(a, b);
}
// 각 원소가 속한 집할 출력
cout << "각 원소가 속한 집합: ";
for (int i = 1 ; i <= v; i++) {
cout << findParent(i) << " ";
}
cout << endl;
// 부모 테이블 내용 출력
cout << "부모 테이블: ";
for (int i = 1 ; i <= v; i++) {
cout << parent[i] << " ";
}
cout << endl;
return 0 ;
}
위의 소스는 노드의 개수(V)이고 union연산의 개수(M)일때, 시간복잡도가 O(VM)이다.
따라서 findParent 함수 부분을 다음과 같이 변경해준다.
int findParent(int x) {
if (parent[x] != x) {
parent[x] = findParent(parent[x]);
}
return parent[x];
}
수정 후에는 시간복잡도가
이다.
해당 부분의 시간복잡도 증명은 다음에 다루겠다
즉, 최종 소스는 다음과 같다.
<2번째 소스 : 수정 후>
#include <iostream>
#include <vector>
using namespace std;
// 노드의 개수(v)와 간선(e)의 개수
// 노드의 개수는 최대 100000개라고 가정
int v, e;
int parent[100001];
// 특정 원소가 속한 집합을 찾기
int findParent(int x) {
if (parent[x] != x) {
parent[x] = findParent(parent[x]);
}
return parent[x];
}
// 두 원소가 속한 집합을 합치기
void unionParent(int x, int y) {
x = findParent(x);
y = findParent(y);
if (x < y) {
parent[y] = x;
}
else {
parent[x] = y;
}
}
int main(void) {
cin >> v >> e;
// 부모테이블 상에서, 부모를 자기 자신으로 초기화
for (int i = 1; i <= v; i++) {
parent[i] = i;
}
// union 연산을 각각 수행
for (int i = 0; i < e; i++) {
int a, b;
cin >> a >> b;
unionParent(a, b);
}
// 각 원소가 속한 집할 출력
cout << "각 원소가 속한 집합: ";
for (int i = 1 ; i <= v; i++) {
cout << findParent(i) << " ";
}
cout << endl;
// 부모 테이블 내용 출력
cout << "부모 테이블: ";
for (int i = 1 ; i <= v; i++) {
cout << parent[i] << " ";
}
cout << endl;
return 0 ;
}
'알고리즘 > Template' 카테고리의 다른 글
[Algorithm][Template] 위상 정렬(Topology Sort) (0) | 2022.01.15 |
---|---|
[Algorithm][Template] 크루스칼 알고리즘 (0) | 2022.01.03 |
[Algorithm][Template] 플로이드 워셜 알고리즘 (0) | 2021.12.29 |
[Algorithm][Template] Dijkstra 최단거리 탐색 (0) | 2021.12.18 |
[Algorithm][Template] Divide and Conquer (0) | 2021.10.20 |