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; } }