알고리즘
Union Find(유니온파인드), 서로소 집합을 활용한 사이클 판별
댕칠이
2023. 9. 13. 11:21
이전에 유니온파인드에 대해 다룬 적이 있다. 유니온파인드는 서로소 집합을 만드는 알고리즘으로, 각기 다른 서로소를 가진 집합을 판별하고 합치는 기술이다. 자세한 내용은 아래의 링크를 참고하길 바란다.
Union Find(유니온 파인드) - 연관 문제: 백준(1717번) 집합의 표현
대표문제: 백준 1717번 - 집합의 표현 https://www.acmicpc.net/problem/1717 1717번: 집합의 표현 초기에 $n+1$개의 집합 $\{0\}, \{1\}, \{2\}, \dots , \{n\}$이 있다. 여기에 합집합 연산과, 두 원소가 같은 집합에 포함
nologic-07.tistory.com
유니온 파인드를 이용하면 무방향 그래프에서 사이클이 발생하는지 알 수 있다. 그 방법은 모든 노드에 대해서 자신과 간선으로 이어져 있는 노드들에 대해 Union을 수행하는 것이다. 만약 사이클이 존재한다면 어떤 시점에서 Union()을 하기위해 find를 할 때 같은 루트 노드를 가지는 두 개의 노드가 존재하게 될 것이다.
초기 노드들의 루트 노드는 자기 자신이다, 1, 2번 노드는 간선이 있기 때문에 union-find가 수행되며,1번 노드가 2번 노드의 루트가 된다. 1, 3번 노드도 역시 간선이 있기 때문에 union-find가 수행되며, 1번 노드가 3번 노드의 루트가 된다. 2, 3번 노드는 union-find에 의해서 루트 노드가 1번으로 변경될 것이다. 4번은 연결된 간선이 없기 때문에 union-find가 수행되지 않는다. 즉, 4번의 루트는 자기 자신이다.
이렇게 무방향 그래프의 사이클이 생긴 경우에는 4번이 2번 노드와 연결되어 있기 때문에 union-find가 수행된다. 4번의 root 노드는 3번, 3번의 root 노드는 1번이기 때문에 find의 결과로 1이 반환되고, 2의 root 노드는 1번이기 때문에 1이 반환된다. 즉 둘이 같은 root 노드 상에 존재하고 있기 때문에 사이클이 있다고 판단할 수 있다.
전체코드
import java.util.*;
public class Main {
// 노드의 개수(V)와 간선(Union 연산)의 개수(E)
// 노드의 개수는 최대 100,000개라고 가정
public static int v, e;
public static int[] parent = new int[100001]; // 부모 테이블 초기화하기
// 특정 원소가 속한 집합을 찾기
public static int findParent(int x) {
// 루트 노드가 아니라면, 루트 노드를 찾을 때까지 재귀적으로 호출
if (x == parent[x]) return x;
return parent[x] = findParent(parent[x]);
}
// 두 원소가 속한 집합을 합치기
public static void unionParent(int a, int b) {
a = findParent(a);
b = findParent(b);
if (a < b) parent[b] = a;
else parent[a] = b;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
v = sc.nextInt();
e = sc.nextInt();
// 부모 테이블상에서, 부모를 자기 자신으로 초기화
for (int i = 1; i <= v; i++) {
parent[i] = i;
}
boolean cycle = false; // 사이클 발생 여부
for (int i = 0; i < e; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
// 사이클이 발생한 경우 종료
if (findParent(a) == findParent(b)) {
cycle = true;
break;
}
// 사이클이 발생하지 않았다면 합집합(Union) 연산 수행
else {
unionParent(a, b);
}
}
if (cycle) {
System.out.println("사이클이 발생했습니다.");
}
else {
System.out.println("사이클이 발생하지 않았습니다.");
}
}
}
코드는 이것이 취업을 위한 코딩 테스트다 with python- 저자 나동빈 책의 JAVA 코드를 참고했다.