Algorithm & Data Structures/BOJ

b1717. μ§‘ν•©μ˜ ν‘œν˜„

Geisha 2025. 5. 6. 19:42

 

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

 

 

 

🧩 μžλ°”λ‘œ ν‘ΈλŠ” μ§‘ν•©μ˜ ν‘œν˜„ 문제 풀이

 


 

πŸ“Œ 문제 κ°œμš”

 

λ°±μ€€ 1717번 μ§‘ν•©μ˜ ν‘œν˜„ λ¬Έμ œλŠ” Disjoint Set(μ„œλ‘œμ†Œ μ§‘ν•©) 자료ꡬ쑰의 κΈ°λ³Έ λ™μž‘μΈ Find와 Union을 κ΅¬ν˜„ν•˜λŠ” λŒ€ν‘œμ μΈ λ¬Έμ œμž…λ‹ˆλ‹€.

 

  • μ—°μ‚° μ’…λ₯˜
    • 0 a b : a와 bκ°€ μ†ν•œ 집합을 ν•©μΉœλ‹€.
    • 1 a b : a와 bκ°€ 같은 집합에 ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€ ν™•μΈν•œλ‹€.
  •  

 


 

πŸ’‘ 예제 μž…λ ₯

7 8
0 1 3
1 1 7
0 7 6
1 7 1
0 3 7
0 4 2
0 1 1
1 1 1

예제 좜λ ₯:

NO
NO
YES

 

 


 

🧠 μ•Œκ³ λ¦¬μ¦˜ μ ‘κ·Ό 방식

 

  • 핡심은 Union-Find μ•Œκ³ λ¦¬μ¦˜μž…λ‹ˆλ‹€.
  • 각 μ›μ†ŒλŠ” μžμ‹ μ΄ μ†ν•œ μ§‘ν•©μ˜ λŒ€ν‘œ(parent)λ₯Ό κ°€λ¦¬ν‚΅λ‹ˆλ‹€.
  • find(x)λ₯Ό 톡해 λŒ€ν‘œλ₯Ό μ°Ύκ³ , union(x, y)λ₯Ό 톡해 두 집합을 λ³‘ν•©ν•©λ‹ˆλ‹€.
  • findμ—λŠ” **경둜 μ••μΆ•(Path Compression)**을 μ μš©ν•΄ μ‹œκ°„ λ³΅μž‘λ„λ₯Ό μ€„μž…λ‹ˆλ‹€.

 


 

🧾 μ½”λ“œ ν•΄μ„€

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

public class Main {
    static int n, m;
    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());
        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        parent = new int[n + 1];

        for (int i = 0; i <= n; i++) parent[i] = i;

        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int op = Integer.parseInt(st.nextToken());
            int a  = Integer.parseInt(st.nextToken());
            int b  = Integer.parseInt(st.nextToken());

            if (op == 0) {
                union(a, b);
            } else {
                sb.append(find(a) == find(b) ? "YES\n" : "NO\n");
            }
        }

        System.out.print(sb);
    }

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

    static void union(int a, int b) {
        int rootA = find(a);
        int rootB = find(b);
        if (rootA != rootB) parent[rootB] = rootA;
    }
}

βœ” find ν•¨μˆ˜λŠ” 경둜 압좕을 μ΄μš©ν•΄ λΆ€λͺ¨λ₯Ό μž¬κ·€μ μœΌλ‘œ μ΅œμƒμœ„ 루트둜 κ°±μ‹ ν•©λ‹ˆλ‹€.

βœ” union ν•¨μˆ˜λŠ” 두 μ›μ†Œμ˜ 루트λ₯Ό μ°Ύμ•„μ„œ λ³‘ν•©ν•©λ‹ˆλ‹€.

βœ” μž…λ ₯이 많기 λ•Œλ¬Έμ— BufferedReader와 StringBuilderλ₯Ό μ‚¬μš©ν•˜μ—¬ μž…μΆœλ ₯ μ„±λŠ₯을 μ΅œμ ν™”ν•©λ‹ˆλ‹€.

 


 

🎯 결둠

 

이 λ¬Έμ œλŠ” Union-Find μ•Œκ³ λ¦¬μ¦˜μ„ μ—°μŠ΅ν•˜κΈ°μ— κ°€μž₯ μ ν•©ν•œ λ¬Έμ œμž…λ‹ˆλ‹€.

특히 경둜 μ••μΆ• 없이 ν’€λ©΄ μ‹œκ°„ μ΄ˆκ³Όκ°€ λ°œμƒν•˜λ―€λ‘œ, find()에 κΌ­ μ΅œμ ν™”λ₯Ό μ μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

 

πŸ‘‰πŸΌ μ„œλ‘œμ†Œ μ§‘ν•© 문제λ₯Ό ν’€ λ•ŒλŠ” 항상 λ‹€μŒ 두 κ°€μ§€λ₯Ό 염두에 λ‘μž:

 

  1. find()μ—λŠ” 경둜 압좕을!
  2. union()μ—λŠ” λŒ€ν‘œλ…Έλ“œ 병합을!