알고리즘/분리집합

[BOJ] 백준 20040 - 사이클 게임 풀이

송승현(SSH) 2023. 3. 17. 13:09

1. 문제

https://www.acmicpc.net/problem/20040

 

20040번: 사이클 게임

사이클 게임은 두 명의 플레이어가 차례대로 돌아가며 진행하는 게임으로, 선 플레이어가 홀수 번째 차례를, 후 플레이어가 짝수 번째 차례를 진행한다. 게임 시작 시 0 부터 n − 1 까지 고유한

www.acmicpc.net

 



2. 풀이

  • Union-Find 알고리즘 사용
  • 게임 당 입력을 받아서 Union-Find 함수를 사용하여 부모 노드를 갱신
  • 핵심 포인트는 Find 함수를 실행했을 때 부모가 같다면 이는 사이클이 발생했다는 의미!!
  • 주요 자료구조
    • int N : 노드수
    • int M : 간선 수
    • int[] parent : 각 노드의 부모를 저장할 배열



3. 풀이 Logic

  • Make-Set을 통해 각 노드의 부모를 자기 자신으로 초기화
  • 각 게임마다 입력을 받고 Union() 함수 시작
    • 입력받은 두 인자를 각각 find() 함수를 통해 부모를 찾는다.
    • 찾은 두 부모의 값을 비교하여 부모를 연결하고 true를 반환
      • 이때 find()를 한 두 부모가 같다면 이는 사이클이 생겼다는 의미이므로 false를 반환
    • 만약 union() 함수에서 false를 리턴 받았다면 그때의 게임 횟수를 result에 넣고 반복문을 끝낸다.



4. 소스 코드

import java.io.*;

import java.util.StringTokenizer;

public class Main {
    static int N; // 노드수
    static int M; // 간선 수
    static int[] parent; // 각 노드의 부모를 저장할 배열
    static int result = 0;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        // 입력
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        // make-Set
        parent = new int[N];
        for (int i = 0; i < N; i++) {
            parent[i] = i;
        }

        // 입력을 받을 때 마다 확인
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());

            // 유니온
            if (!union(x, y)) {
                result = i + 1;
                break;
            }
        }

        bw.write(Integer.toString(result));
        bw.flush();
        bw.close();
        br.close();
    }

    // 유니온
    private static boolean union(int x, int y) {
        int px = find(x);
        int py = find(y);

        if (px > py) {
            parent[py] = px;
            return true;
        } else if (px < py){
            parent[px] = py;
            return true;
        } else {  // 유니온을 했을 때 부모가 같으면 사이클이 발생한 것
            return false;
        }
    }

    // 부모를 찾는 find
    private static int find(int idx) {
        if (idx == parent[idx])
            return idx;

        return parent[idx] = find(parent[idx]);
    }
}



5. 점수

70 / 100