Algorithm🌊/λ°±μ€€(BOJ)

[λ°±μ€€ / JAVA] 1717번, μ§‘ν•©μ˜ ν‘œν˜„ (Union-Find)

μ–΄μ œμ‹œμž‘ 2024. 12. 23. 14:07

문제

μ΄ˆκΈ°μ— n+1$n+1$개의 μ§‘ν•© {0}, {1}, {2},…, {n} 이 μžˆλ‹€. 여기에 ν•©μ§‘ν•© μ—°μ‚°κ³Ό, 두 μ›μ†Œκ°€ 같은 집합에 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” 연산을 μˆ˜ν–‰ν•˜λ €κ³  ν•œλ‹€.

집합을 ν‘œν˜„ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.


μž…λ ₯

첫째 쀄에 n, m이 μ£Όμ–΄μ§„λ‹€. m은 μž…λ ₯으둜 μ£Όμ–΄μ§€λŠ” μ—°μ‚°μ˜ κ°œμˆ˜μ΄λ‹€. λ‹€μŒ m개의 μ€„μ—λŠ” 각각의 연산이 μ£Όμ–΄μ§„λ‹€. 합집합은 0 a b의 ν˜•νƒœλ‘œ μž…λ ₯이 μ£Όμ–΄μ§„λ‹€. μ΄λŠ” aκ°€ ν¬ν•¨λ˜μ–΄ μžˆλŠ” μ§‘ν•©κ³Ό, bκ°€ ν¬ν•¨λ˜μ–΄ μžˆλŠ” 집합을 ν•©μΉœλ‹€λŠ” μ˜λ―Έμ΄λ‹€. 두 μ›μ†Œκ°€ 같은 집합에 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” 연산은 1 a b의 ν˜•νƒœλ‘œ μž…λ ₯이 μ£Όμ–΄μ§„λ‹€. μ΄λŠ” a와 bκ°€ 같은 집합에 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” 연산이닀.


좜λ ₯

1둜 μ‹œμž‘ν•˜λŠ” μž…λ ₯에 λŒ€ν•΄μ„œ a와 bκ°€ 같은 집합에 ν¬ν•¨λ˜μ–΄ 있으면 "YES" λ˜λŠ” "yes"λ₯Ό, κ·Έλ ‡μ§€ μ•Šλ‹€λ©΄ "NO" λ˜λŠ” "no"λ₯Ό ν•œ 쀄에 ν•˜λ‚˜μ”© 좜λ ₯ν•œλ‹€.


풀이

μœ λ‹ˆμ˜¨ νŒŒμΈλ“œμ— λŒ€ν•΄ μ•Œκ³  μžˆλ‹€λ©΄ λΉ λ₯΄κ²Œ ν’€μˆ˜ 있던 λ¬Έμ œμž…λ‹ˆλ‹€. (λ¬Όλ‘  λ‚˜λŠ” 이걸 ν•˜λ©΄μ„œ μ•Œκ²Œ λ˜μ—ˆμ§€λ§Œ)

 

λΆ€λͺ¨ λ…Έλ“œλ₯Ό λ§Œλ“€μ–΄ 놓고 각 λΆ€λͺ¨κ°€ μ–΄λ–€ λ…Έλ“œμΈμ§€ μ„€μ •ν•΄ μ£ΌλŠ” μž‘μ—…μ΄λΌκ³  μƒκ°ν•˜λ©΄ λ©λ‹ˆλ‹€.

처음 Parents[i]λŠ” i(본인)을 μ„€μ •ν•œ μƒνƒœμž…λ‹ˆλ‹€.

그리고 0을 λ°›μœΌλ©΄ 두 λ…Έλ“œλ₯Ό union(ν•©μ§‘ν•©) ν•©λ‹ˆλ‹€. μ €λŠ” μž‘μ€ nodeλ₯Ό λΆ€λͺ¨λ‘œ μ„€μ •ν•˜λŠ” μž‘μ—…μ„ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ, 1을 λ°›κ²Œλ˜λ©΄ 두 λ…Έλ“œκ°€ 같은 λΆ€λͺ¨λ₯Ό κ°–κ³  μžˆλŠ”μ§€ connected()λ₯Ό 톡해 ν™•μΈν•˜μ—¬ Yes와 Noλ₯Ό λ°˜ν™˜ν•˜λŠ” μž‘μ—…μ„ ν•˜κ²Œ λ©λ‹ˆλ‹€.

 

ν•΄λ‹Ή μ†ŒμŠ€ μ½”λ“œμž…λ‹ˆλ‹€.

import java.io.*;
import java.util.*;

/**
 * 문제: 1717_μ§‘ν•©μ˜ν‘œν˜„
 * μ΄ˆκΈ°μ— $n+1$개의 μ§‘ν•© $\\{0\\}, \\{1\\}, \\{2\\}, \\dots , \\{n\\}$이 μžˆλ‹€. 여기에 ν•©μ§‘ν•© μ—°μ‚°κ³Ό,
 * 두 μ›μ†Œκ°€ 같은 집합에 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” 연산을 μˆ˜ν–‰ν•˜λ €κ³  ν•œλ‹€.
 * 집합을 ν‘œν˜„ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.
 * μž…λ ₯ :
 * 첫째 쀄에 $n$, $m$이 μ£Όμ–΄μ§„λ‹€. $m$은 μž…λ ₯으둜 μ£Όμ–΄μ§€λŠ” μ—°μ‚°μ˜ κ°œμˆ˜μ΄λ‹€.
 * λ‹€μŒ $m$개의 μ€„μ—λŠ” 각각의 연산이 μ£Όμ–΄μ§„λ‹€.
 * 합집합은 $0$ $a$ $b$의 ν˜•νƒœλ‘œ μž…λ ₯이 μ£Όμ–΄μ§„λ‹€.
 * μ΄λŠ” $a$κ°€ ν¬ν•¨λ˜μ–΄ μžˆλŠ” μ§‘ν•©κ³Ό, $b$κ°€ ν¬ν•¨λ˜μ–΄ μžˆλŠ” 집합을 ν•©μΉœλ‹€λŠ” μ˜λ―Έμ΄λ‹€.
 * 두 μ›μ†Œκ°€ 같은 집합에 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” 연산은 $1$ $a$ $b$의 ν˜•νƒœλ‘œ μž…λ ₯이 μ£Όμ–΄μ§„λ‹€.
 * μ΄λŠ” $a$와 $b$κ°€ 같은 집합에 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” 연산이닀.
 */
public class Main {
    static int[] parents;

    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());

        parents = new int[n+1];
        for (int i = 1; i <= n; i++) {
            parents[i] = i;
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int check = Integer.parseInt(st.nextToken());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            if (check == 0){
                union(a,b);
            }
            else {
                if (connected(a, b)){
                    sb.append("YES\\n");
                }
                else {
                    sb.append("NO\\n");
                }
            }
        }
        System.out.println(sb);
        br.close();
    }

    static int find(int x) {
        if (parents[x] != x) return parents[x] = find(parents[x]);
        return parents[x];
    }

    static void union(int x, int y) {
        int a = find(x);
        int b = find(y);
        if(a > b){
            parents[b] = a;
        }
        else{
            parents[a] = b;
        }
    }

    static boolean connected(int a, int b) {
        return find(a) == find(b);
    }
}