์๋ก์ ์งํฉ(Disjoint Set)๊ณผ Union-Find ์๊ณ ๋ฆฌ์ฆ
์๋ก์ ์งํฉ(Disjoint Set)
์๋ก์ ์งํฉ(์ํธ๋ฐฐํ ์งํฉ)์ ์๋ก ์ค๋ณต๋์ด ํฌํจ๋ ์์๊ฐ ์๋ ์งํฉ์ ์๋ฏธํจ. ๋ค์ ๋งํด ๊ต์งํฉ์ด ์๋ ์งํฉ!
๋ฐ๋ผ์ ์งํฉ์ ์ํ ํ๋์ ํน์ ์์๋ฅผ ํตํด ๊ฐ ์งํฉ์ ๊ตฌ๋ณํ ์ ์๊ณ , ์ด ์์๋ฅผ ๋ํ์(representative)๋ผ๊ณ ํจ.
์๋ก์๋?
์ํ์์์ ์๋ก์๋ ์ ์๋ ๋คํญ์ ๊ฐ ์ต๋ ๊ณต์ฝ์๊ฐ 1์ธ ๊ด๊ณ๋ฅผ ๋งํจ
์๋ก์ ์งํฉ์ ํํ
-
์ฐ๊ฒฐ ๋ฆฌ์คํธ
- ๊ฐ์ ์งํฉ ์์๋ค์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ก ๊ด๋ฆฌ
- ์ฐ๊ฒฐ ๋ฆฌ์คํธ์ ๊ฐ์ฅ ์์ ์์นํ ์์๋ฅผ ๋ํ์๋ก ์ค์
- ๊ฐ ์์๋ ์งํฉ์ ๋ํ ์์๋ฅผ ๊ฐ๋ฆฌํค๋ ๋งํฌ๋ฅผ ๊ฐ์ง
-
ํธ๋ฆฌ
- ํ๋์ ์งํฉ์ ํ๋์ ํธ๋ฆฌ๋ก ๊ด๋ฆฌ
- ์์ ๋ ธ๋๊ฐ ๋ถ๋ชจ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๋ ํํ์ด๊ณ , ๋ฃจํธ ๋ ธ๋๊ฐ ๋ํ์๊ฐ ๋จ
์๋ก์ ์งํฉ์ ์ฐ์ฐ
-
Make-Set(x)
: ์ ์ผํ ๋ฉค๋ฒx
๋ฅผ ํฌํจํ๋ ์๋ก์ด ์งํฉ์ ์์ฑ- ์ด๊ธฐ ์ธํ ๊ฐ๋ ์ผ๋ก, ๋ชจ๋ ์์๋ค์ด ์๊ธฐ ์์ ๋ง์ ์์๋ก ํ๋ ์งํฉ์ ๊ตฌ์ฑํ๋ฉด ์๋ก์ ์งํฉ๋ค์ด ๋ง๋ค์ด์ง
- ๋ฐ๋ผ์ N๊ฐ์ ์์๋ก ์์๊ฐ 1๊ฐ์ฉ์ธ N๊ฐ์ ์งํฉ์ด ์์ฑ๋จ
-
Find-Set(x)
:x
๋ฅผ ํฌํจํ๋ ์งํฉ์ ์ฐพ๋ ์ฐ์ฐ- ๋ํ์๋ฅผ ์ฐพ๋ ์ฐ์ฐ
- ์์ ์ด ๊ณง ๋ํ์์ผ ์ ์๊ณ , ์๋๋ผ๋ฉด ๋ถ๋ชจ์ ๋ํ์๋ฅผ ์ฌ๊ท์ ์ผ๋ก ์ฐพ์๊ฐ ์์ ์ ๋ํ์๋ฅผ ์ฐพ์
-
Union(x, y)
:x
์y
๋ฅผ ํฌํจํ๋ ๋ ์งํฉ์ ๊ฒฐํฉํ๋ ์ฐ์ฐ๋ํ์๋ฅผ ํตํ ๊ฒฐํฉ!!!
- ๋ํ์๊ฐ ๊ฐ์ ๊ฐ์ ์งํฉ์ด๋ฉด ์ฐ์ฐํ์ง ์๊ณ , ์๋๋ผ๋ฉด
y
๊ฐ ์ํ๋ ์งํฉ์ ๋ํ์๋ฅผx
๊ฐ ์ํ ์งํฉ์ ๋ํ์๋ก ๋์น
๊ธฐ๋ณธ ์๋ก์ ์งํฉ ์ฐ์ฐ์ ๋ฌธ์ ์
์๋ก์ ์งํฉ์ ์๋ก๊ฐ ๊ฐ์ ์งํฉ์ธ์ง ํ์ธํ๊ธฐ ์ํด์ ๊ฐ ์์์ ๋ํ์์ธ ๋ฃจํธ๋ ธ๋๊น์ง ํ๊ณ ์ฌ๋ผ๊ฐ์ผ ํ๋ค. ๋ํ ๋ ์งํฉ์ ๊ฒฐํฉํ ๋๋ ์์๋ผ๋ฆฌ ๊ฒฐํฉํ๋ ๊ฒ์ด ์๋๋ผ ๋ํ์๋ผ๋ฆฌ ๊ฒฐํฉํ๋ ๋ฐฉ์์ ์ทจํ๊ธฐ๋๋ฌธ์ ์ด ๋๋ ์ญ์๋ ๋ํ์๋ฅผ ์ฐพ๊ธฐ ์ํด ๋ฃจํธ ๋ ธ๋๊น์ง ํ๊ณ ์ฌ๋ผ๊ฐ์ผ ํ๋ค.
๋ง์ฝ find-set()
ํน์ union()
์ ์๋ํ๋ ์์๋ค์ด ํธ๋ฆฌ์ ๋ง๋จ์ ์์นํด์๋ค๋ฉด ๋ฃจํธ ๋
ธ๋๊น์ง ํ์ํด ์ฌ๋ผ๊ฐ๋ ๊ณผ์ ์์ ๋น์ฉ์ด ๊ฝค๋ ์๋ชจ๋ ํ
๋ฐ ์๊น์ง ์์๊ฐ?!
์๋ก์ ์งํฉ์์์ ํธ๋ฆฌ๋ ๋ถ๋ชจ ๋ ธ๋์ ์์ ๋ ธ๋ ๊ฐ ๊ณ์ธต ๊ด๊ณ๋ฅผ ํํํ๊ณ ์์ง ์๊ธฐ๋๋ฌธ์(๋จ์ง ๊ฐ์ ์งํฉ์ ์ํ ์์๋ฅผ ํํํ ๊ฒ ๋ฟ) ์ด ๊ณ์ธต ๊ด๊ณ๋ฅผ ํด์งํด๋ ๋๋ค. ๋ฐ๋ผ์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ์ด์ฉํ ๊ตฌํ์ด ํจ์ฌ ํจ์จ์ ์ด๋ค.
ํ์ง๋ง ์ธ์์ ๋๊ณ ํธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ ์งํ๋ฉด์๋ ์ฐ์ฐ์ ํจ์จ์ ์ผ๋ก ํ ์ ์๋ ์๊ณ ๋ฆฌ์ฆ๋ ์กด์ฌํ๋ค.
์ฐ์ฐ ํจ์จ์ ๋์ธ ์๋ก์ ์ฐ์ฐ
Union by Rank(rank๋ฅผ ์ด์ฉํ union)
- ๊ฐ ๋ ธ๋๋ ์์ ์ ๋ฃจํธ๋ก ํ๋ ์๋ธ ํธ๋ฆฌ์ ๋์ด๋ฅผ rank๋ก ์ ์ฅํ๊ณ ์์
- ๋ ์งํฉ์ ๋ํด union์ ์๋ํ ๋, rank๊ฐ ๋ฎ์ ์งํฉ์ rank๊ฐ ๋์ ์งํฉ์ ๊ฒฐํฉํจ
- ์ต์ข ์ ์ผ๋ก ํ๋๊ฐ ๋ ์งํฉ์ rank๋ rank๊ฐ ๋์๋ ์งํฉ์ rank์ด๋ฏ๋ก rank์ ๋ณํ๊ฐ ์๊ธฐ์ง ์์
- ๋จ, ๊ฒฐํฉํ๋ ค๋ ๋ ์งํฉ์ rank๊ฐ ๋์ผํ๋ค๋ฉด, rank๊ฐ 1๊ฐ๋ ๋์ด๋ ์๋ฐ์ ์์
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(๊ฒฝ๋ก ์์ถ)
Find-Set()
์ ํตํด ์ ๊ทผํ๊ฒ ๋๋ ์์ ์ ๋ชจ๋ ๋ถ๋ชจ ๋ ธ๋๋ค์ด ์ง์ ๋ฃจํธ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๋๋ก pointer๋ฅผ ๋ณ๊ฒฝ- ๊ฒฐ๊ณผ์ ์ผ๋ก ๊ฐ ์์์ ๋ถ๋ชจ ๋ ธ๋๋ ์์ ์ด ์ํ ์งํฉ์ ๋ํ์๊ฐ ๋จ
- ๋ํ์๊ฐ ์ฌ๋ฌ ์์๋ค์ ํ๊บผ๋ฒ์ ๋ฌผ๊ณ ์๋ ํํ
- path compression์
Find-Set()
์ฐ์ฐ์ ์ํํ ๋ ์ด๋ฃจ์ด์ง๋ฏ๋ก ์ฐ์ฐ์ ํ์ง ์์ผ๋ฉด path compression๋ ์ผ์ด๋์ง ์์
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()
์ฐ์ฐ ๊ฒฐ๊ณผ ์งํฉ์ ์์๊ฐ ๋ ๋ง์๋ ๋ํ์๋ ์งํฉ ์์ ๊ฐ์๊ฐ ๋์ด๋๊ณ , ์งํฉ ์์๊ฐ ๋ ์ ์๋ ๋ํ์๋ ์์ ์ ๋ํ์๋ฅผ ์งํฉ์ ์์๊ฐ ๋ ๋ง์๋ ๋ํ์๋ก ๋์นํจ์ผ๋ก์จ ๊ฒฐํฉ ํํ
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;
}
}