์„œ๋กœ์†Œ ์ง‘ํ•ฉ(Disjoint Set)๊ณผ Union-Find ์•Œ๊ณ ๋ฆฌ์ฆ˜

์„œ๋กœ์†Œ ์ง‘ํ•ฉ(Disjoint Set)

์„œ๋กœ์†Œ ์ง‘ํ•ฉ(์ƒํ˜ธ๋ฐฐํƒ€ ์ง‘ํ•ฉ)์€ ์„œ๋กœ ์ค‘๋ณต๋˜์–ด ํฌํ•จ๋œ ์›์†Œ๊ฐ€ ์—†๋Š” ์ง‘ํ•ฉ์„ ์˜๋ฏธํ•จ. ๋‹ค์‹œ ๋งํ•ด ๊ต์ง‘ํ•ฉ์ด ์—†๋Š” ์ง‘ํ•ฉ!

๋”ฐ๋ผ์„œ ์ง‘ํ•ฉ์— ์†ํ•œ ํ•˜๋‚˜์˜ ํŠน์ • ์›์†Œ๋ฅผ ํ†ตํ•ด ๊ฐ ์ง‘ํ•ฉ์„ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ๊ณ , ์ด ์›์†Œ๋ฅผ ๋Œ€ํ‘œ์ž(representative)๋ผ๊ณ  ํ•จ.

์„œ๋กœ์†Œ๋ž€?

์ˆ˜ํ•™์—์„œ์˜ ์„œ๋กœ์†Œ๋Š” ์ •์ˆ˜๋‚˜ ๋‹คํ•ญ์‹ ๊ฐ„ ์ตœ๋Œ€ ๊ณต์•ฝ์ˆ˜๊ฐ€ 1์ธ ๊ด€๊ณ„๋ฅผ ๋งํ•จ

์„œ๋กœ์†Œ ์ง‘ํ•ฉ์˜ ํ‘œํ˜„

  1. ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ

    • ๊ฐ™์€ ์ง‘ํ•ฉ ์›์†Œ๋“ค์„ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋กœ ๊ด€๋ฆฌ
    • ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๊ฐ€์žฅ ์•ž์— ์œ„์น˜ํ•œ ์›์†Œ๋ฅผ ๋Œ€ํ‘œ์ž๋กœ ์„ค์ •
    • ๊ฐ ์›์†Œ๋Š” ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ ์›์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋งํฌ๋ฅผ ๊ฐ€์ง
  2. ํŠธ๋ฆฌ

    • ํ•˜๋‚˜์˜ ์ง‘ํ•ฉ์„ ํ•˜๋‚˜์˜ ํŠธ๋ฆฌ๋กœ ๊ด€๋ฆฌ
    • ์ž์‹ ๋…ธ๋“œ๊ฐ€ ๋ถ€๋ชจ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํ˜•ํƒœ์ด๊ณ , ๋ฃจํŠธ ๋…ธ๋“œ๊ฐ€ ๋Œ€ํ‘œ์ž๊ฐ€ ๋จ

์„œ๋กœ์†Œ ์ง‘ํ•ฉ์˜ ์—ฐ์‚ฐ

  1. Make-Set(x) : ์œ ์ผํ•œ ๋ฉค๋ฒ„ x๋ฅผ ํฌํ•จํ•˜๋Š” ์ƒˆ๋กœ์šด ์ง‘ํ•ฉ์„ ์ƒ์„ฑ

    • ์ดˆ๊ธฐ ์„ธํŒ… ๊ฐœ๋…์œผ๋กœ, ๋ชจ๋“  ์›์†Œ๋“ค์ด ์ž๊ธฐ ์ž์‹ ๋งŒ์„ ์›์†Œ๋กœ ํ•˜๋Š” ์ง‘ํ•ฉ์„ ๊ตฌ์„ฑํ•˜๋ฉด ์„œ๋กœ์†Œ ์ง‘ํ•ฉ๋“ค์ด ๋งŒ๋“ค์–ด์ง
    • ๋”ฐ๋ผ์„œ N๊ฐœ์˜ ์›์†Œ๋กœ ์›์†Œ๊ฐ€ 1๊ฐœ์”ฉ์ธ N๊ฐœ์˜ ์ง‘ํ•ฉ์ด ์ƒ์„ฑ๋จ
  2. Find-Set(x) : x๋ฅผ ํฌํ•จํ•˜๋Š” ์ง‘ํ•ฉ์„ ์ฐพ๋Š” ์—ฐ์‚ฐ

    • ๋Œ€ํ‘œ์ž๋ฅผ ์ฐพ๋Š” ์—ฐ์‚ฐ
    • ์ž์‹ ์ด ๊ณง ๋Œ€ํ‘œ์ž์ผ ์ˆ˜ ์žˆ๊ณ , ์•„๋‹ˆ๋ผ๋ฉด ๋ถ€๋ชจ์˜ ๋Œ€ํ‘œ์ž๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ์ฐพ์•„๊ฐ€ ์ž์‹ ์˜ ๋Œ€ํ‘œ์ž๋ฅผ ์ฐพ์Œ
  3. Union(x, y) : x์™€ y๋ฅผ ํฌํ•จํ•˜๋Š” ๋‘ ์ง‘ํ•ฉ์„ ๊ฒฐํ•ฉํ•˜๋Š” ์—ฐ์‚ฐ

    • ๋Œ€ํ‘œ์ž๋ฅผ ํ†ตํ•œ ๊ฒฐํ•ฉ!!!
    • ๋Œ€ํ‘œ์ž๊ฐ€ ๊ฐ™์•„ ๊ฐ™์€ ์ง‘ํ•ฉ์ด๋ฉด ์—ฐ์‚ฐํ•˜์ง€ ์•Š๊ณ , ์•„๋‹ˆ๋ผ๋ฉด y๊ฐ€ ์†ํ–ˆ๋˜ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๋ฅผ x๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๋กœ ๋Œ€์น˜

๊ธฐ๋ณธ ์„œ๋กœ์†Œ ์ง‘ํ•ฉ ์—ฐ์‚ฐ์˜ ๋ฌธ์ œ์ 

์„œ๋กœ์†Œ ์ง‘ํ•ฉ์€ ์„œ๋กœ๊ฐ€ ๊ฐ™์€ ์ง‘ํ•ฉ์ธ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ฐ ์›์†Œ์˜ ๋Œ€ํ‘œ์ž์ธ ๋ฃจํŠธ๋…ธ๋“œ๊นŒ์ง€ ํƒ€๊ณ  ์˜ฌ๋ผ๊ฐ€์•ผ ํ•œ๋‹ค. ๋˜ํ•œ ๋‘ ์ง‘ํ•ฉ์„ ๊ฒฐํ•ฉํ•  ๋•Œ๋„ ์›์†Œ๋ผ๋ฆฌ ๊ฒฐํ•ฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋Œ€ํ‘œ์ž๋ผ๋ฆฌ ๊ฒฐํ•ฉํ•˜๋Š” ๋ฐฉ์‹์„ ์ทจํ•˜๊ธฐ๋•Œ๋ฌธ์— ์ด ๋•Œ๋„ ์—ญ์‹œ๋‚˜ ๋Œ€ํ‘œ์ž๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ๋ฃจํŠธ ๋…ธ๋“œ๊นŒ์ง€ ํƒ€๊ณ  ์˜ฌ๋ผ๊ฐ€์•ผ ํ•œ๋‹ค.

๋งŒ์•ฝ find-set() ํ˜น์€ union()์„ ์‹œ๋„ํ•˜๋Š” ์›์†Œ๋“ค์ด ํŠธ๋ฆฌ์˜ ๋ง๋‹จ์— ์œ„์น˜ํ•ด์žˆ๋‹ค๋ฉด ๋ฃจํŠธ ๋…ธ๋“œ๊นŒ์ง€ ํƒ์ƒ‰ํ•ด ์˜ฌ๋ผ๊ฐ€๋Š” ๊ณผ์ •์—์„œ ๋น„์šฉ์ด ๊ฝค๋‚˜ ์†Œ๋ชจ๋ ํ…๋ฐ ์•„๊น์ง€ ์•Š์€๊ฐ€?!

์„œ๋กœ์†Œ ์ง‘ํ•ฉ์—์„œ์˜ ํŠธ๋ฆฌ๋Š” ๋ถ€๋ชจ ๋…ธ๋“œ์™€ ์ž์‹ ๋…ธ๋“œ ๊ฐ„ ๊ณ„์ธต ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•˜๊ณ  ์žˆ์ง€ ์•Š๊ธฐ๋•Œ๋ฌธ์—(๋‹จ์ง€ ๊ฐ™์€ ์ง‘ํ•ฉ์— ์†ํ•œ ์›์†Œ๋ฅผ ํ‘œํ˜„ํ•œ ๊ฒƒ ๋ฟ) ์ด ๊ณ„์ธต ๊ด€๊ณ„๋ฅผ ํ•ด์ง€ํ•ด๋„ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ด์šฉํ•œ ๊ตฌํ˜„์ด ํ›จ์”ฌ ํšจ์œจ์ ์ด๋‹ค.

ํ•˜์ง€๋งŒ ์„ธ์ƒ์€ ๋„“๊ณ  ํŠธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ์—ฐ์‚ฐ์„ ํšจ์œจ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜๋„ ์กด์žฌํ•œ๋‹ค.

์—ฐ์‚ฐ ํšจ์œจ์„ ๋†’์ธ ์„œ๋กœ์†Œ ์—ฐ์‚ฐ

Union by Rank(rank๋ฅผ ์ด์šฉํ•œ union)

Union by Rank1

Union by Rank2

  • ๊ฐ ๋…ธ๋“œ๋Š” ์ž์‹ ์„ ๋ฃจํŠธ๋กœ ํ•˜๋Š” ์„œ๋ธŒ ํŠธ๋ฆฌ์˜ ๋†’์ด๋ฅผ rank๋กœ ์ €์žฅํ•˜๊ณ  ์žˆ์Œ
  • ๋‘ ์ง‘ํ•ฉ์— ๋Œ€ํ•ด union์„ ์‹œ๋„ํ•  ๋•Œ, rank๊ฐ€ ๋‚ฎ์€ ์ง‘ํ•ฉ์„ rank๊ฐ€ ๋†’์€ ์ง‘ํ•ฉ์— ๊ฒฐํ•ฉํ•จ
  • ์ตœ์ข…์ ์œผ๋กœ ํ•˜๋‚˜๊ฐ€ ๋œ ์ง‘ํ•ฉ์˜ rank๋Š” rank๊ฐ€ ๋†’์•˜๋˜ ์ง‘ํ•ฉ์˜ rank์ด๋ฏ€๋กœ rank์˜ ๋ณ€ํ™”๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š์Œ
  • ๋‹จ, ๊ฒฐํ•ฉํ•˜๋ ค๋Š” ๋‘ ์ง‘ํ•ฉ์˜ rank๊ฐ€ ๋™์ผํ•˜๋‹ค๋ฉด, rank๊ฐ€ 1๊ฐœ๋Š” ๋Š˜์–ด๋‚  ์ˆ˜๋ฐ–์— ์—†์Œ
Java
class RankDisjointSet {
    int N;              // ์ „์ฒด ์›์†Œ ๊ฐœ์ˆ˜
    int[] parents;      // ๊ฐ ์›์†Œ์˜ ๋ถ€๋ชจ ์ธ๋ฑ์Šค ์ €์žฅ
    int[] ranks;        // ๊ฐ ์›์†Œ์˜ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋†’์ด ์ €์žฅ

    // ์ดˆ๊ธฐ ์„œ๋กœ์†Œ ์ง‘ํ•ฉ ์ƒ์„ฑ
    public void makeSet() {
        parents = new int[N];
        ranks = new int[N];

        // ์ดˆ๊ธฐ ์„œ๋กœ์†Œ ์ง‘ํ•ฉ์€ ์ž๊ธฐ ์ž์‹ ๋งŒ์„ ํฌํ•จํ•œ ์ง‘ํ•ฉ์ด๋ฏ€๋กœ ๋Œ€ํ‘œ์ž๋Š” ์ž๊ธฐ ์ž์‹ ์„ ๊ฐ€๋ฆฌํ‚ด
        for (int i=0; i<N; i++) parents[i] = i;
    }

    // ๋Œ€ํ‘œ์ž ์ฐพ๊ธฐ
    public int findSet(int x) {
        if (parents[x] == x) return x;        // ๋Œ€ํ‘œ์ž๊ฐ€ ์ž๊ธฐ ์ž์‹ ์ด๋ฉด ์ž์‹ ์„ ๋ฆฌํ„ด
        return parents[x] = findSet(parents[x]);           // ์•„๋‹ˆ๋ฉด ์ž์‹ ์˜ ๋ถ€๋ชจ์˜ ๋Œ€ํ‘œ์ž๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ์ฐพ์•„ ์ž์‹ ์ด ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๋ฅผ ์ฐพ์Œ
    }

    // ๋‘ ์›์†Œ๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ ๊ฒฐํ•ฉ
    public boolean union(int x, int y) {
        int xRoot = findSet(x);     // ์›์†Œ x๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž
        int yRoot = findSet(y);     // ์›์†Œ y๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž

        // ๋งŒ์•ฝ ๋‘ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๊ฐ€ ๊ฐ™์œผ๋ฉด, ์ฆ‰ ๋‘ ์›์†Œ๊ฐ€ ๊ฐ™์€ ์ง‘ํ•ฉ์— ํฌํ•จ๋  ๊ฒฝ์šฐ ๊ฒฐํ•ฉ ์‹คํŒจ
        if (xRoot == yRoot) return false;

        // rank ๊ธฐ์ค€ ๊ฒฐํ•ฉ
        if (ranks[xRoot] <= ranks[yRoot]) {      // rank๊ฐ€ ๋” ํฐ ์ชฝ์œผ๋กœ ๊ฒฐํ•ฉ
            parents[xRoot] = yRoot;              // rank๊ฐ€ ์ž‘์€ ์ชฝ ๋ถ€๋ชจ๋ฅผ rank๊ฐ€ ํฐ ์ชฝ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๋กœ ์„ค์ •
            
            if (ranks[xRoot] == ranks[yRoot]) ranks[yRoot]++;     // rank๊ฐ€ ๋™์ผํ•œ ์ง‘ํ•ฉ ๊ฒฐํ•ฉ ์‹œ rank๊ฐ€ 1๊ฐœ ๋Š˜์–ด๋‚  ์ˆ˜๋ฐ–์— ์—†์Œ
        } else parents[yRoot] = xRoot;

        return true;
    }
}

Path Compression(๊ฒฝ๋กœ ์••์ถ•)

Path Compression

  • Find-Set()์„ ํ†ตํ•ด ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋Š” ์ž์‹ ์˜ ๋ชจ๋“  ๋ถ€๋ชจ ๋…ธ๋“œ๋“ค์ด ์ง์ ‘ ๋ฃจํŠธ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก pointer๋ฅผ ๋ณ€๊ฒฝ
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ ๊ฐ ์›์†Œ์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋Š” ์ž์‹ ์ด ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๊ฐ€ ๋จ
  • ๋Œ€ํ‘œ์ž๊ฐ€ ์—ฌ๋Ÿฌ ์›์†Œ๋“ค์„ ํ•œ๊บผ๋ฒˆ์— ๋ฌผ๊ณ ์žˆ๋Š” ํ˜•ํƒœ
  • path compression์€ Find-Set() ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ ์—ฐ์‚ฐ์„ ํ•˜์ง€ ์•Š์œผ๋ฉด path compression๋„ ์ผ์–ด๋‚˜์ง€ ์•Š์Œ
Java
class PathCompressDisjointSet {
    int N;              // ์ „์ฒด ์›์†Œ ๊ฐœ์ˆ˜
    int[] parents;      // ๊ฐ ์›์†Œ์˜ ๋ถ€๋ชจ ์ธ๋ฑ์Šค ์ €์žฅ

    // ์ดˆ๊ธฐ ์„œ๋กœ์†Œ ์ง‘ํ•ฉ ์ƒ์„ฑ
    public void makeSet() {
        parents = new int[N];

        // ์ดˆ๊ธฐ ์„œ๋กœ์†Œ ์ง‘ํ•ฉ์€ ์ž๊ธฐ ์ž์‹ ๋งŒ์„ ํฌํ•จํ•œ ์ง‘ํ•ฉ์ด๋ฏ€๋กœ ๋Œ€ํ‘œ์ž๋Š” ์ž๊ธฐ ์ž์‹ ์„ ๊ฐ€๋ฆฌํ‚ด
        for (int i=0; i<N; i++) parents[i] = i;
    }

    // ๋Œ€ํ‘œ์ž ์ฐพ๊ธฐ
    public int findSet(int x) {
        if (parents[x] == x) return x;               // ๋Œ€ํ‘œ์ž๊ฐ€ ์ž๊ธฐ ์ž์‹ ์ด๋ฉด ์ž์‹ ์„ ๋ฆฌํ„ด
        return parents[x] = findSet(parents[x]);     // ์•„๋‹ˆ๋ฉด ์ž์‹ ์˜ ๋ถ€๋ชจ์—๊ฒŒ ๋ฐ”๋กœ ์ž์‹ ์ด ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๋ฅผ ๋Œ€์น˜(path compression)
    }

    // ๋‘ ์›์†Œ๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ ๊ฒฐํ•ฉ
    public boolean union(int x, int y) {
        int xRoot = findSet(x);     // ์›์†Œ x๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž
        int yRoot = findSet(y);     // ์›์†Œ y๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž

        // ๋งŒ์•ฝ ๋‘ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๊ฐ€ ๊ฐ™์œผ๋ฉด, ์ฆ‰ ๋‘ ์›์†Œ๊ฐ€ ๊ฐ™์€ ์ง‘ํ•ฉ์— ํฌํ•จ๋  ๊ฒฝ์šฐ ๊ฒฐํ•ฉ ์‹คํŒจ
        if (xRoot == yRoot) return false;

        parents[yRoot] = xRoot;     // ์ฒซ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋“ค์–ด์˜จ ์›์†Œ๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์— ๋‘๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ง‘ํ•ฉ ๊ฒฐํ•ฉ(๋ฌด์กฐ๊ฑด ๋Œ€ํ‘œ์ž๋ผ๋ฆฌ ๊ฒฐํ•ฉ)
        return true;
    }
}

๊ฐ ์„œ๋กœ์†Œ ์ง‘ํ•ฉ์˜ ์›์†Œ ๊ฐœ์ˆ˜ ๊ตฌํ•˜๊ธฐ

์ง€๊ธˆ๊นŒ์ง€ ๊ตฌํ˜„ํ•œ ์„œ๋กœ์†Œ ์ง‘ํ•ฉ์€ parents ๋ฐฐ์—ด์— ์ž์‹ ์˜ ๋ถ€๋ชจ ์ธ๋ฑ์Šค๋ฅผ ์ €์žฅํ•ด๋‘์–ด ๋Œ€ํ‘œ์ž๊นŒ์ง€ ์ฐพ์•„ ์˜ฌ๋ผ๊ฐ€๊ฑฐ๋‚˜, ์•„๋‹ˆ๋ฉด ๋ฐ”๋กœ ๋Œ€ํ‘œ์ž๋ฅผ ์ €์žฅํ•˜์—ฌ ๋ฃจํŠธ ๋…ธ๋“œ๊นŒ์ง€ ์ฐพ์•„ ์˜ฌ๋ผ๊ฐ€๋Š” ์‹œ๊ฐ„์„ ๋‹จ์ถ•ํ•˜๊ธฐ๋„ ํ–ˆ๋‹ค.

์ด๋ฒˆ์—๋Š” parents ๋ฐฐ์—ด์„ ์•„์ฃผ ์กฐ๊ธˆ ์† ๋ด์„œ ๊ฐ ์ง‘ํ•ฉ์˜ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ๊ตฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. ์‰ฝ๊ฒŒ ๋งํ•ด parents ๋ฐฐ์—ด์— ๋ถ€๋ชจ ์ธ๋ฑ์Šค๋‚˜ ๋Œ€ํ‘œ์ž๋ฅผ ์ €์žฅํ•˜๋Š” ๋Œ€์‹  ์ง‘ํ•ฉ์˜ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ์ €์žฅํ•œ๋‹ค. ๊ธฐ๋ณธ ์›๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ์ตœ์ดˆ Make-Set() ์—ฐ์‚ฐ ์‹œ parents ๋ฐฐ์—ด์— ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž(์ตœ์ดˆ์—๋Š” ์ž๊ธฐ ์ž์‹ ์ด ๋Œ€ํ‘œ์ž์ž„) ์ธ๋ฑ์Šค๋ฅผ ์ €์žฅํ•˜๋Š” ๋Œ€์‹ , ์ง‘ํ•ฉ ์›์†Œ ๊ฐœ์ˆ˜ * (-1)๋ฅผ ์ €์žฅํ•จ

    • ์ด๋•Œ, parents ๋ฐฐ์—ด์—๋Š” ๋ฌด์กฐ๊ฑด ์ง‘ํ•ฉ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๊ฐ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž์ธ ๊ฒฝ์šฐ์—๋งŒ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ์ €์žฅ. ๋‚˜๋จธ์ง€ ์›์†Œ๋“ค์€ ์—ญ์‹œ ๋ถ€๋ชจ ์ธ๋ฑ์Šค๋‚˜ ๋Œ€ํ‘œ์ž ์ธ๋ฑ์Šค๋ฅผ ์ €์žฅ
    • (-1)์„ ๊ณฑํ•˜๋Š” ์ด์œ  : ์ผ๋ฐ˜ ์›์†Œ๋“ค์ด ์ €์žฅํ•œ ์ธ๋ฑ์Šค์™€ ๋Œ€ํ‘œ์ž ์›์†Œ๊ฐ€ ์ €์žฅํ•œ ์ง‘ํ•ฉ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐœ์ˆ˜๋Š” (-1)์„ ๊ณฑํ•˜์—ฌ ์Œ์ˆ˜ ์ƒํƒœ๋กœ ์ €์žฅ. ๋”ฐ๋ผ์„œ ์‹ค์ œ ์ง‘ํ•ฉ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ ˆ๋Œ“๊ฐ’์„ ์ทจํ•˜๋ฉด ๋จ.
  • ์ดํ›„ union() ์—ฐ์‚ฐ ์‹œ ๋‘ ์›์†Œ๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๋ฅผ ์ฐธ์กฐํ•˜๋ฉด ๊ฒฐ๊ตญ ๋‘ ์ง‘ํ•ฉ ๊ฐ๊ฐ์˜ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ๊ตฌํ•  ์ˆ˜ ์žˆ๊ณ , ์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ฒฐํ•ฉ์„ ์‹œ๋„ํ•จ. ์ง‘ํ•ฉ ์›์†Œ ๊ฐœ์ˆ˜๊ฐ€ ์ ์€ ์ชฝ์—์„œ ๋งŽ์€ ์ชฝ์œผ๋กœ ๊ฒฐํ•ฉ
  • union() ์—ฐ์‚ฐ ๊ฒฐ๊ณผ ์ง‘ํ•ฉ์˜ ์›์†Œ๊ฐ€ ๋” ๋งŽ์•˜๋˜ ๋Œ€ํ‘œ์ž๋Š” ์ง‘ํ•ฉ ์›์†Œ ๊ฐœ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚˜๊ณ , ์ง‘ํ•ฉ ์›์†Œ๊ฐ€ ๋” ์ ์—ˆ๋˜ ๋Œ€ํ‘œ์ž๋Š” ์ž์‹ ์˜ ๋Œ€ํ‘œ์ž๋ฅผ ์ง‘ํ•ฉ์˜ ์›์†Œ๊ฐ€ ๋” ๋งŽ์•˜๋˜ ๋Œ€ํ‘œ์ž๋กœ ๋Œ€์น˜ํ•จ์œผ๋กœ์จ ๊ฒฐํ•ฉ ํ‘œํ˜„
Java
class CountDisjointSet {
    int N;              // ์ „์ฒด ์›์†Œ ๊ฐœ์ˆ˜
    int[] parents;      // ๊ฐ ์›์†Œ์˜ ๋ถ€๋ชจ ์ธ๋ฑ์Šค ์ €์žฅ

    // ์ดˆ๊ธฐ ์„œ๋กœ์†Œ ์ง‘ํ•ฉ ์ƒ์„ฑ
    public void makeSet() {
        parents = new int[N];

        // ์ดˆ๊ธฐ ์„œ๋กœ์†Œ ์ง‘ํ•ฉ ์ƒ์„ฑ ์‹œ ๋Œ€ํ‘œ์ž๋Š” ์ž๊ธฐ ์ž์‹ ์ด๊ณ  ์›์†Œ ๊ฐœ์ˆ˜๋„ ์ž๊ธฐ ์ž์‹  ํ•˜๋‚˜๋ฟ์ด๋ฏ€๋กœ -1๋กœ ์ดˆ๊ธฐํ™”
        for (int i=0; i<N; i++) parents[i] = -1;
    }

    // ๋Œ€ํ‘œ์ž ์ฐพ๊ธฐ
    public int findSet(int x) {
        if (parents[x] < 0) return x;                // ๋Œ€ํ‘œ์ž๋งŒ์ด ์›์†Œ ๊ฐœ์ˆ˜์ธ ์Œ์ˆ˜ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ž๊ธฐ ์ž์‹ ์ด ๋Œ€ํ‘œ์ž์ด๋ฉด ์ž์‹ ์„ ๋ฐ˜ํ™˜
        return parents[x] = findSet(parents[x]);     // ์•„๋‹ˆ๋ฉด ์ž์‹ ์˜ ๋ถ€๋ชจ์—๊ฒŒ ๋ฐ”๋กœ ์ž์‹ ์ด ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๋ฅผ ๋Œ€์น˜(path compression)
    }

    // ๋‘ ์›์†Œ๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ ๊ฒฐํ•ฉ
    public boolean union(int x, int y) {
        int xRoot = findSet(x);     // ์›์†Œ x๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž
        int yRoot = findSet(y);     // ์›์†Œ y๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž

        // ๋งŒ์•ฝ ๋‘ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž๊ฐ€ ๊ฐ™์œผ๋ฉด, ์ฆ‰ ๋‘ ์›์†Œ๊ฐ€ ๊ฐ™์€ ์ง‘ํ•ฉ์— ํฌํ•จ๋  ๊ฒฝ์šฐ ๊ฒฐํ•ฉ ์‹คํŒจ
        if (xRoot == yRoot) return false;

        // ๋‘ ์ง‘ํ•ฉ์˜ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ๋น„๊ตํ•˜์—ฌ ์›์†Œ๊ฐ€ ๋” ๋งŽ์€ ์ชฝ์œผ๋กœ ๊ฒฐํ•ฉ
        if (parents[xRoot] < parents[yRoot]) {     // ์›์†Œ ๊ฐœ์ˆ˜ ๋งŽ์œผ๋ฉด(์Œ์ˆ˜๊ฐ€ ์ปค์ง€๋ฉด ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•˜๋Š” ์ ˆ๋Œ“๊ฐ’์ด ๋” ์ปค์ง)
            parents[xRoot] += parents[yRoot];      // ์›์†Œ ๊ฐœ์ˆ˜ ์ ์€ ์ชฝ์˜ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ์›์†Œ ๊ฐœ์ˆ˜ ๋งŽ์€ ์ชฝ์œผ๋กœ ๋„˜๊ฒจ์ฃผ๊ณ 
            parents[yRoot] = xRoot;                // ์›์†Œ ๊ฐœ์ˆ˜ ์ ์€ ์ชฝ์˜ ๋Œ€ํ‘œ์ž์˜ ๋ถ€๋ชจ๋ฅผ ์›์†Œ ๊ฐœ์ˆ˜ ๋งŽ์€ ์ชฝ ๋Œ€ํ‘œ์ž๋กœ ์„ค์ •
        } else {
            parents[yRoot] += parents[xRoot];
            parents[xRoot] = yRoot;
        }
        return true;
    }
}