https://www.acmicpc.net/problem/10451
코드설명
유니온 파인드(UnionFind, Disjoint Set) + DFS(깊이우선탐색) 를 활용합니다.
굳이 UnionFind를 사용하지 않고, Visited[] 배열을 생성한뒤 한번이라도 탐색했다면 Visited[] 를 true로 바꿔주면서 처리하면 더 간단하다.
UnionFind를 사용하고 싶어서 UnionFind를 사용했다.
코드
정답코드입니다.(처음에 틀린 함수도 함께 포함)
package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.StringTokenizer;
public class Main {
private static int N, T, K;
private static int answer = 0;
private static int[] standard;
private static int[] arr;
private static int[] parent;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
T = Integer.parseInt(st.nextToken());
while(T-- > 0) {
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
standard = new int[N + 1];
arr = new int[N + 1];
parent = new int[N+1];
answer = 0;
st = new StringTokenizer(br.readLine());
//UnionFind 사용시 이렇게 N+1로 처리하는게 편하다.
for(int i=1;i<=N;i++) {
standard[i] = i;
parent[i] = i;
arr[i] = Integer.parseInt(st.nextToken());
}
for(int i=1; i<=N; i++) {
for(int j=1; j<=N; j++) {
findParent(j);
}
//아직 싸이클에 없는 경우입니다.
if( findParent(i) == i) {
if( simul2(i, i) == true) {
answer += 1;
}
}
}
System.out.println(answer);
}
}
private static boolean simul2(int first, int idx) {
if(first == arr[idx]) {
return true;
}
simul2(first, arr[idx]);
unionFind(idx, arr[idx]);
return true;
}
//틀린 코드이다.
//사이클은 반드시 처음 숫자값으로 돌아온다는 것을 놓쳤다.
//또, unionFind 작업이 재귀가 끝나고 처리되는 것이 아닌 먼저 처리하고 깊이우선탐색이 지속되기에
//올바르게 재귀가 작동하지 않는다.
private static boolean simul(int idx) {
//처음에 실수한 부분. idx == arr[idx] 처리를 안했다. 본인이 본인을 바라보는 사이클을 체크해야한다.
if( (findParent(idx) != idx) || idx == arr[idx]) {
return true;
}
for(int i=1; i<=N; i++) {
System.out.print(parent[i]+" ");
}
System.out.println();
System.out.println("why stackOverFlow?");
unionFind(idx, arr[idx]);
return simul(arr[idx]);
}
private static int findParent(int x) {
if(x == parent[x]) return x;
else return parent[x] = findParent(parent[x]);
}
private static void unionFind(int a, int b) {
a = findParent(a);
b = findParent(b);
if(a < b) parent[b] = a;
else parent[a] = b;
}
}