
int root[MAX_SIZE];
for(int i = 0; i < MAX_SIZE; i++) {
root[i] = i;
}
int find(int x) {
if(root[x] == x) {
return x;
} else {
return find[root[x]]; // 재귀를 통해 부모 노드의 값을 찾는다.
}
}
void union(int x, int y) {
x = find(x); // x의 부모 노드
y = find(y); // y의 부모 노드
root[y] = x; // y의 부모 노드를 x로 바꿔주면서 x와 y를 이어준다.
}
1로 시작하는 입력에 대해 a와 b가 같은 집합에 포함되어 있으면 "YES" 그렇지 않으면 "NO"를 한 줄에 하나씩 출력한다.
2초
Union-Find 알고리즘을 활용해보자.
- 0 a b의 형태로 나오면 union 작업을 수행하고 1 a b의 형태로 나오면 find 작업을 수행하여 답을 구해보자.
- Union-Find를 알기 전엔 이 문제를 Set을 이용해 집합을 합쳐 중복 수를 없애 find 작업이 나오면 해당 Set에 값이 있는 지 판단하였었는데 이는 메모리 초과를 피할 수 없었다.
이중 반복 수행 불가능
- N이 1,000,000개이고 M이 100,000이기 때문에 이중으로 반복 수행하는 경우 시간 초과가 발생한다.
import java.util.*;
import java.io.*;
public class Main {
static int[] arr;
static int find(int a) {
if(arr[a] == a) {
return a;
} else {
return find(arr[a]); // 부모 노드 탐색
}
}
static void union(int a, int b) {
int x = find(a);
int y = find(b);
arr[y] = x; // x를 y의 부모로 지정하여 두 집합을 합치는 작업
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
arr = new int[n+1];
for(int i = 0; i <= n; i++) {
arr[i] = i;
}
StringBuilder sb = new StringBuilder();
for(int i = 0; i < m; i++) {
st = new StringTokenizer(br.readLine());
int digits = Integer.parseInt(st.nextToken());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
if(digits == 1) {
if(find(a) == find(b)) sb.append("YES").append("\n"); // 두 부모가 같으면 같은 트리에 속해있다.
else sb.append("NO").append("\n");
} else {
union(a,b);
}
}
System.out.println(sb);
}
}
Reference