본문 바로가기

CodingTEST

[백준 1717] 집합의 표현 (JAVA)

반응형

백준 1717번 문제 - 집합의 표현 

 

1717번: 집합의 표현

초기에 $n+1$개의 집합 $\{0\}, \{1\}, \{2\}, \dots , \{n\}$이 있다. 여기에 합집합 연산과, 두 원소가 같은 집합에 포함되어 있는지를 확인하는 연산을 수행하려고 한다. 집합을 표현하는 프로그램을 작

www.acmicpc.net


문제 분석

 

  • N개의 수가 주어지면 N개는 각각 다른 집합으로 구성된다.
  • M개의 수식이 주어지며, 수식은 다음 2가지 종류가 있다.
    • 0 a b : b 집합을 a 집합에 포함 시킨다.
    • 1 a b : a와 b가 동일한 집합이면 YES, 아니면 NO 출력

 

해결 키 포인트

 

  • 유니온 파인드(union-find) 개념 사용
  • 0도 포함되므로 배열 구현할 때, N개 배열 생성하고 a,b에서 -1을 하면 안된다. N+1개 배열 생성!

유니온 파인트 (union-find)

여러 노드가 있을 때 특정 2개의 노드를 연결해 1개의 집합으로 묶는 union 연산과 두 노드가 같은 집합에 속해 있는지 확인하는 find 연산으로 구성되어 있는 알고리즘이다.

 

  • union 연산 : 각 노드가 속한 집합을 1개로 합치는 연산이다. 노드 a, b가 a ∈ A, b ∈ B일 때 union(a, b)는 A∪B를 말한다.
  • find 연산 : 특정 노드 a에 관해 a가 속한 집합의 대표 노드를 반환하는 연산이다. 노드 a, b가 a ∈ A일 때 find(a)는 A 집합의 대표 노드를 반환한다. 

 

Union 연산 알고리즘
  • 1차원 배열을 이용해서, i번째 값은 i로 변수 초기화한다. ( 대표 노드는 본인 )
  • union(a, b) 연산은 a와 b의 대표 노드를 알아내 'b 대표 노드'의 value( list['b 대표 노드'] )을 'a 대표 노드'로 변경한다.
    • index == list[index] : 해당 index가 집합의 대표 노드
      index !=  list[index] : 대표 노드를 알아내야 함 ( 배열의 list[index]와 list[list[index]] 비교 )
    • list['b 대표 노드'] = 'a 대표 노드' 로 b 집합을 a 집합에 포함시킨다.

 

Find 연산 알고리즘
  • 대상 노드 배열에 index 값과 value 값이 동일한지 확인
  • 동일하지 않으면 value 값이 가리키는 index 위치로 이동
  • 이동 위치의 index 값과 value 값이 같을 때까지 앞 방법들을 반복 (재귀함수로)
  • 대표 노드에 도달하면 재귀함수를 빠져나오면서 거치는 모든 노드 값을 대표 노드 값으로 변경

코드
import java.io.*;
import java.util.*;

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

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

        // N개의 집합 생성
        collection = new int [N+1];
        for(int i=0;i<=N;i++) {
            collection[i] = i;
        }

        // M개의 연산 실행
        for(int i=0;i<M;i++) {
            // 연산 종류(0: union, 1: find) a b 입력
            st = new StringTokenizer(br.readLine());
            int operator = Integer.parseInt(st.nextToken());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());

            // operator가 0 일 때 : a,b 집합 합치기 : a,b union
            if(operator == 0) {
                union(a, b);
            }

            // operator가 1 일 때 : a와 b가 같은 그룹인지 확인 : find
            if(operator == 1) {
                if (find(a) == find(b))
                    bw.write("YES\n"); // 같은 그룹일 경우 yes 출력
                else
                    bw.write("NO\n");  // 아닐 경우 no 출력
            }
        }
        bw.flush();
        bw.close();
    }

    public static void union(int a, int b) {
        int firstA = a, firstB = b;

        // a가 집합 대표가 아닐 경우 (a와 collection[a]가 동일 하지 않을 경우)
        if(a != collection[a])
            firstA = find(a); //  a 집합 대표 찾기 ( find(a) )


        // b가 집합 대표가 아닐 경우 (b와 collection[b]가 동일 하지 않을 경우)
        if(b != collection[b])
            firstB = find(b); //  b 집합 대표 찾기 ( find(b) )

        // b 집합의 대표를 a 집합의 대표로
        collection[firstB] = firstA;
    }

    public static int find(int a) {
        // a가 집합 대표일 경우 (a와 collection[a]가 동일 할 경우)
        if (a == collection[a])
            return a;

        //  a가 집합 대표가 아닐 경우
        collection[a] = find(collection[a]);
        return collection[a];
    }
}
 
반응형

'CodingTEST' 카테고리의 다른 글

[백준 1043] 거짓말 (JAVA)  (1) 2023.08.27
[백준 1976] 여행 가자 (JAVA)  (0) 2023.08.26
[백준 2251] 물통 (JAVA)  (0) 2023.08.25
[백준 1707] 이분 그래프 (JAVA)  (0) 2023.08.24
[백준 1325] 효율적인 해킹 (JAVA)  (0) 2023.08.23