DisjointSet-unionFind

Disjoint Set

๋ฒˆ์—ญํ•˜๋ฉด ์„œ๋กœ์†Œ ์ง‘ํ•ฉ์œผ๋กœ ์„œ๋กœ ์ค‘๋ณต ๋˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„ ์ง‘ํ•ฉ๋“ค๋กœ ์ด๋ฃจ์–ด์ง„ ์ง‘ํ•ฉ(set).

ํ•œ๋งˆ๋””๋กœ ๊ต์ง‘ํ•ฉ์ด ์กด์žฌ ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์ง‘ํ•ฉ๋“ค๋กœ ์ด๋ฃจ์–ด์ง„ ์ง‘ํ•ฉ.

Union-Find

Union : ๋‘๊ฐœ์˜ ์ง‘ํ•ฉ์„ ํ•˜๋‚˜์˜ ์ง‘ํ•ฉ์œผ๋กœ ํ•ฉ์น˜๋Š” ๊ฒƒ.

Find : ์–ด๋–ค ์›์†Œ๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ ์ด ์›์†Œ๊ฐ€ ์†ํ•œ ์ง‘ํ•ฉ์„ ๋ฐ˜ํ™˜ํ•˜๋Š”(์ฐพ๋Š”) ๊ฒƒ.

์ง‘ํ•ฉ๋“ค์„ tree๊ตฌ์กฐ๋กœ ๋‚˜ํƒ€๋‚ด์–ด ํ•ด๋‹น์›์†Œ๊ฐ€ ์–ด๋–ค ์ง‘ํ•ฉ์— ์†ํ•˜๋Š”์ง€ ํŒ๋‹จํ• ๋•Œ ๊ฐ ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ๊ฐ’(root)์„ ์ด์šฉํ•ด์„œ ์ง‘ํ•ฉ์ด ๊ฐ™์€์ง€๋ฅผ ๋น„๊ต.

๊ตฌํ˜„ ๋ฐฉ๋ฒ•

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

typedef struct node{
    int data;
    struct node* parent;
    struct node* next;
}node;

void MakeSet(node* p,int x){
     p->data = x;
     p->parent = p;//์ฒ˜์Œ์€ ๋‹ค ์›์†Œ๊ฐ€ ํ•˜๋‚˜์”ฉ์žˆ๋Š” ์ง‘ํ•ฉ์ด๋ฏ€๋กœ ์ž๊ธฐ ์ž์‹ ์ด root
     p->next=null;
}

void Find(node* p,int x){
    if(p->parent->data == x) return x;  //root๊ฐ’์ด ์ž๊ธฐ ์ž์‹ ์ด๋ผ๋ฉด ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ๊ฐ’
    else return Find(p->parent,x);  //์žฌ๊ท€์ ์œผ๋กœ ์ง‘ํ•ฉ ๋Œ€ํ‘œ๊ฐ’ ์ฐพ๊ธฐ
}

void Union(node* p1,node* p2,int x,int y){
    x = Find(p1,x);
    y = Find(p2,y);
    p1->next = p2;
    p2->parent = p1;
}

  • Disjoint Set Forest ( Tree )

int root[n];

void MakeSet(int x){
     root[x] = x;    //์ฒ˜์Œ์€ ๋‹ค ์›์†Œ๊ฐ€ ํ•˜๋‚˜์”ฉ์žˆ๋Š” ์ง‘ํ•ฉ์ด๋ฏ€๋กœ ์ž๊ธฐ ์ž์‹ ์ด root
}

void Find(int x){
    if(root[x] == x) return x;  //root๊ฐ’์ด ์ž๊ธฐ ์ž์‹ ์ด๋ผ๋ฉด ์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ๊ฐ’
    else return Find(root[x]);  //์žฌ๊ท€์ ์œผ๋กœ ์ง‘ํ•ฉ ๋Œ€ํ‘œ๊ฐ’ ์ฐพ๊ธฐ
}

void Union(int x,int y){
    x = Find(x);
    y = Find(y);
    root[y] = x;
}

์‹œ๊ฐ„ ๋ณต์žก๋„

์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ๋กœ ๊ตฌํ˜„์‹œ O(nlgn)์˜ ์‹œ๊ฐ„์„ ๊ฐ–์œผ๋ฉฐ Tree๋กœ ๊ตฌํ˜„ํ•ด๋„ ๋ถˆ๊ท ํ˜•ํ•œ ํŠธ๋ฆฌ (์˜ˆ : skewd tree)์™€ ๊ฐ™๊ฒŒ ๋˜๋ฉด ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ์™€ ๋‹ค๋ฅผ ๊ฒƒ์ด ์—†์–ด์ง„๋‹ค.

๋ฌธ์ œ์ 

find์‹œ์— ์žฌ๊ท€์ ์œผ๋กœ ์ฐพ๊ธฐ ๋•Œ๋ฌธ์— ๋งŒ์•ฝ์— set์˜ tree๊ตฌ์กฐ๊ฐ€ ์„ ํ˜•์ ์ธ ํ˜•ํƒœ๋ผ๊ณ  ํ•œ๋‹ค๋ฉด ์ตœ์•…์˜ ๊ฒฝ์šฐ๋กœ O(n)๋งŒํผ์˜ ์‹œ๊ฐ„์ด ์†Œ์š” ๋˜๊ฒŒ ๋œ๋‹ค.

โžก path compression (๊ฒฝ๋กœ ์••์ถ•)๊ธฐ๋ฒ• ์‚ฌ์šฉ

๋˜ํ•œ, union์‹œ์— ๊นŠ์ด๊ฐ€ ์ž‘์€ ํŠธ๋ฆฌ์— ๊นŠ์ด๊ฐ€ ๊นŠ์€ ํŠธ๋ฆฌ๋ฅผ ๋ถ™์ด๊ฒŒ ๋˜๋ฉด ๊นŠ์ด๊ฐ€ ๋” ์ฆ๊ฐ€ํ•˜์—ฌ ์‹œ๊ฐ„์— ์•…์˜ํ–ฅ์„ ์ค€๋‹ค.

โžก union by rank ๊ธฐ๋ฒ• ์‚ฌ์šฉ

path compression (๊ฒฝ๋กœ ์••์ถ•)

find ์—ฐ์‚ฐ ์ˆ˜ํ–‰์‹œ๋งˆ๋‹ค ํŠธ๋ฆฌ์˜ ๊ตฌ์กฐ๋ฅผ ํ‰ํ‰ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•.

๊ฐ root๊ฐ’์„ ์žฌ๊ท€์ ์œผ๋กœ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ด ์•„๋‹Œ ํ•ด๋‹น ์ง‘ํ•ฉ์˜ ์†ํ•˜๋Š” ์›์†Œ๋Š” ๋ชจ๋‘ ๋™์ผํ•œ root๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•

void Find(int x){
    /*find์ˆ˜ํ–‰๋งˆ๋‹ค ํ•ด๋‹น parent๊ฐ’์„ root๋กœ ์ดˆ๊ธฐํ™”*/
    if(root[x] != x) root[x] = Find(root[x]);
    else return root[x];
}

union by rank

ํ•ญ์ƒ ๊นŠ์ด๊ฐ€ ๊นŠ์€ ํŠธ๋ฆฌ์— ์ž‘์€ ํŠธ๋ฆฌ๋ฅผ ๋ถ™์—ฌ ๊นŠ์ด๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•.

๊นŠ์ด๊ฐ€ ์„œ๋กœ ๊ฐ™์€ ํŠธ๋ฆฌ๋ผ๋ฉด, ๊นŠ์ด๋ฅผ 1์ฆ๊ฐ€ ์‹œํ‚จ๋‹ค.

int root[n];
int rank[n];

void MakeSet(int x){
    root[x] = x;    //์ฒ˜์Œ์€ ๋‹ค ์›์†Œ๊ฐ€ ํ•˜๋‚˜์”ฉ์žˆ๋Š” ์ง‘ํ•ฉ์ด๋ฏ€๋กœ ์ž๊ธฐ ์ž์‹ ์ด root
    rank[x] = 0;    //๊นŠ์ด๋„ 0์œผ๋กœ ์ดˆ๊ธฐํ™”
}

void Union(int x,int y){
    x = Find(x);    //์ž…๋ ฅ๋ฐ›์€ x๊ฐ’์˜ root๊ฐ’์„ ์ €์žฅ
    y = Find(y);    //์ž…๋ ฅ๋ฐ›์€ y๊ฐ’์˜ root๊ฐ’์„ ์ €์žฅ

    if(x==y)  return; //root๊ฐ€ ๊ฐ™๋‹ค๋ฉด ๊ฐ™์€ ์ง‘ํ•ฉ

    if(rank[x] < rank[y])  root[x] = y; //x์˜ root๋ฅผ y๋กœ ๋ณ€๊ฒฝ
    else if(rank[x] > rank[y]) root[y]= x; //y์˜ root๋ฅผ x๋กœ ๋ณ€๊ฒฝ
    else{
        root[y] = x;
        rank[x]++;  //๊นŠ์ด๊ฐ€ ๊ฐ™๋‹ค๋ฉด x์— y๋ฅผ ๋ถ™์˜€์œผ๋ฏ€๋กœ x๊นŠ์ด ์ฆ๊ฐ€
    }

๋‘ ๊ธฐ๋ฒ•์„ ์ ์šฉ ํ›„ ์‹œ๊ฐ„ ๋ณต์žก๋„

O(lgn)

ํ™œ์šฉ

Disjoint Set ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ์ง‘ํ•ฉ์˜ ๋ถ„ํ• ์„ ๋ชจ๋ธ๋ง ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌด๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„(undirected graph) ์˜ ์—ฐ๊ฒฐ๋œ ์š”์†Œ๋“ค์„ ์ถ”์  ํ•  ์ˆ˜ ์žˆ์–ด, ์‚ฌ์ดํด์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ / ๊ฐ™์€ ์š”์†Œ์— ์†ํ•˜๋Š”์ง€ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋Œ€ํ‘œ์ ์œผ๋กœ MST๋ฅผ ์ฐพ๋Š” Kruskal ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ์ด์šฉ๋œ๋‹ค.

Last updated