1. ๋ถ๋ฆฌ ์งํฉ(Disjoint Set)
์๋ก์ ์งํฉ์ด๋ผ๊ณ ๋ถ๋ฆฌ์ฐ๋ ๋ถ๋ฆฌ ์งํฉ์ ์ค๋ณต๋๋ ๋ถ๋ถ์ด ๋ฐ์ํ์ง ์๋๋ก ๋ชจ๋ ์์๋ฅผ ๋ถ๋ฆฌํ ์งํฉ์ ๋งํ๋ค. ๊ทธ๋ฅ ์๋ก ์ค๋ณต๋์ง ์๋ ๋ถ๋ถ ์งํฉ๋ค๋ก ์ด๋ฃจ์ด์ง ์์๋ค์ ๋ํด ์ ์ฅํ๊ณ ์๋ ์๋ฃ๊ตฌ์กฐ์ด๋ค.
- ์ ์ฒด ์งํฉ U์ ๋ํด, U์ ๋ถ๋ฆฌ ์งํฉ A์ B๋ ๋ค์๊ณผ ๊ฐ์ ์กฐ๊ฑด๋ค์ ๋ง์กฑํ๋ค.
- A, B๋ U์ ๋ถ๋ถ ์งํฉ์ด๋ค.
- A, B๋ ๊ณตํต ์์๋ฅผ ๊ฐ์ง์ง ์๋๋ค.
- A, B์ ํฉ ์งํฉ์ด ์ ์ฒด ์งํฉ U์ด๋ค. (A, B ๋ ๋ค ์ํ์ง ์๋ U์ ์์๊ฐ ์์ด์ผ ํ๋ค.)
2. ์ ๋์จ ํ์ธ๋(Union-Find)
์ ๋์จ ํ์ธ๋๋ ๋ถ๋ฆฌ ์งํฉ์ ๊ตฌํํ๋ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก, ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ํํํ๋ ๊ฒ์ด ๊ฐ์ฅ ํจ์จ์ ์ด(๋ผ๊ณ ํ)๋ค.
๋จผ์ , ๊ฐ ๋ ธ๋ ๋ณ๋ก ๋ถ๋ชจ ๋ ธ๋ ๋ฒํธ๋ฅผ ๊ธฐ๋กํ๋ค. ๊ทธ๋ผ ๊ทธ๋ํ๊ฐ ํธ๋ฆฌ ํํ๋ก ํํ๋๋ค.
- ์ต์์ ๋
ธ๋์ธ root ๋
ธ๋๋ผ๋ฉด ๋ถ๋ชจ ๋
ธ๋์ ๋ฒํธ๋ ์๊ธฐ ์์ ์ ๋ฒํธ์ด๋ค.
- ์ด root ๋ ธ๋๋ก ๊ทธ๋ฃน์ ๊ตฌ๋ณํ ์ ์๋ค.
- ๊ฐ ๋ ธ๋๊ฐ ๊ฐ์ ๊ทธ๋ฃน์ธ์ง ํ์ธํ๋ ๊ฒ์ DFS ๋ฑ์ ํ์์ ๊ฑฐ์น์ง ์๊ณ , ๋ถ๋ชจ ๋ ธ๋๊ฐ ์ผ์นํ๋์ง๋ก ํ๋ณํ๋ ๊ฒ์ด๋ค.
- ํ ๋ ธ๋์ ๊ทธ๋ฃน๊ณผ ๋ค๋ฅธ ํ ๋ ธ๋์ ๊ทธ๋ฃน์ด ํฉ์ณ์ง๋ค๋ฉด, ๋ถ๋ชจ ๋ ธ๋ ๋ฒํธ๋ฅผ ๋ค๋ฅธ ํ ๋ ธ๋์ ๋ถ๋ชจ ๋ ธ๋๋ก ์ง์ ํ๋ ์์ผ๋ก ํธ๋ฆฌ๋ฅผ ๋ณํฉํ ์ ์๋ค.
(1) makeSet(x)
์ด๊ธฐํ ์์ . x๋ฅผ ์ ์ผํ ์์๋ก ํ๋ ์๋ก์ด ์งํฉ์ ๋ง๋ ๋ค.
var parent = Array(0...n)
- 0์์ n๊น์ง์ ๋ ธ๋์ ๋ํ ๋ถ๋ชจ ๋ ธ๋ ๋ฒํธ๋ฅผ ๊ธฐ๋กํ ๋ฐฐ์ด์ ์ด๊ธฐํํ๋ค.
(2) find(x)
x๊ฐ ์ํ ์งํฉ์ ๋ํ ๊ฐ์ธ root ๋ ธ๋๋ฅผ ๋ฐํํ๋ค. ์ฆ, x๊ฐ ์ด๋ค ์งํฉ, ์ด๋ค ๊ทธ๋ฃน์์ ์ํด ์๋์ง ์ฐพ๋๋ค.
func find(_ x: Int) -> Int {
if x == parent[x] {
return x // ๋ฃจํธ ๋
ธ๋๋ ๋ถ๋ชจ ๋
ธ๋ ๋ฒํธ๊ฐ ์๊ธฐ ์์ ์ ๋ฒํธ์ด๋ค. ๋ฐ๋ผ์ ๋ฃจํธ ๋
ธ๋์ด๋ฏ๋ก ๋ฆฌํด
} else {
return parent[x] // ๋ถ๋ชจ ๋
ธ๋๋ก ๊ฑฐ์ฌ๋ฌ ์ฌ๋ผ๊ฐ๋ ์ค........
}
}
- ์ฌ๊ท๋ฅผ ์ด์ฉํ์ฌ ๋ถ๋ชจ ๋ ธ๋๋ฅผ ์ฐพ๋๋ค.
- ๋ถ๋ชจ ๋ ธ๋์ ๋ฒํธ๊ฐ ์๊ธฐ ์์ ์ ๋ฒํธ๋ผ๋ฉด ์ฌ๊ธฐ๋ root ๋ ธ๋์ ๋๋ค..๋ฆฌํดํ๋ค.
- ์ฌ๊ท๋ฅผ ์ด์ฉํด์ ๋ถ๋ชจ ๋ ธ๋๋ก ๊ฑฐ์ฌ๋ฌ ์ฌ๋ผ๊ฐ๋ค.
func find(_ x: Int) -> Int {
if x != parent[x] {
parent[x] = find(parent[x])
}
return parent[x]
}
- ๊ฒฝ๋ก ์์ถ(Path Compression)์ ํตํ ์ต์ ํ ์ฝ๋์ด๋ค.
- ํ๋์ ๋ ธ๋์ ๋ํด find ์ฐ์ฐ์ ํ ๋๋ง๋ค ๊ทธ ๋ ธ๋์ ๋ถ๋ชจ ๋ ธ๋๋ฅผ ํญ์ root ๋ ธ๋๋ก ๋ง๋ค์ด์ค๋ค๋ฉด, root ๋ ธ๋๋ฅผ ์ฐพ์ ๊ฑฐ์ฌ๋ฌ ์ฌ๋ผ๊ฐ ํ์๊ฐ ์์ด์ง๋ค. find ์ฐ์ฐ ์ ์ค๋ณต๋๋ ์ฐ์ฐ๋ค์ ์ค์ฌ์ฃผ๊ธฐ ๋๋ฌธ์ ๋ ํจ์จ์ ์ผ๋ก root ๋ ธ๋๋ฅผ ์ฐพ์ ์ ์(๋ค๊ณ ํ)๋ค.
(3) union(x, y)
x๊ฐ ์ํ ์งํฉ๊ณผ y๊ฐ ์ํ ์งํฉ์ ํฉ์น๋ค. ์ฆ, ๋ ๊ฐ์ ํธ๋ฆฌ๋ฅผ ๋ณํฉํ๋ค.
func union(_ x: Int, _ y: Int) {
let rootX = find(x)
let rootY = find(y)
if rootX != rootY {
parent[rootX] = rootY
}
}
- x, y ๊ฐ๊ฐ ์ต์์ root ๋ ธ๋ rootX, rootY๋ฅผ find ์ฐ์ฐ์ ํตํด์ ์ฐพ๋๋ค.
- ๋ง์ฝ root ๋ ธ๋๊ฐ ๋ค๋ฅด๋ค๋ฉด, ์ด๋ ์๋ก ๋ค๋ฅธ ํธ๋ฆฌ ๊ทธ๋ฃน์ด๋ฏ๋ก, ํ ์ชฝ์ ํธ๋ฆฌ๋ฅผ ๋ค๋ฅธ ํ ์ชฝ์ ๋ถ์ธ๋ค. ํ ์ชฝ์ root ๋ ธ๋์ ๋ถ๋ชจ ๋ ธ๋๋ฅผ ๋ค๋ฅธ ํ ์ชฝ์ผ๋ก ๋ฑ๋กํ๋ฉด ๋๋ค.
var rank = [Int](repeating: 0, count: n + 1)
func union(_ x: Int, _ y: Int) {
var rootX = find(x)
var rootY = find(y)
if rootX != rootY {
if rank[rootX] < rank[rootY] {
parent[rootX] = rootY // ๋์ด๊ฐ ๋ฎ์ผ๋ฉด(์์ผ๋ฉด) ๋์ด๊ฐ ๋์ ๋ฐ์ ๋ถ์ธ๋ค(๋ถ๋ชจ ๋
ธ๋๋ก ๋ฑ๋ก)
} else rank[rootX] > rank[rootY] {
parent[rootY] = rootX // ํธ๋ฆฌ์ ๋์ด๊ฐ ๋์ ์ชฝ์ด ๋ฃจํธ๊ฐ ๋๋ ์
} else {
parent[rootX] = rootY // ๋์ด๊ฐ ๊ฐ์ผ๋ฉด ์ผ๋จ x์ ๋ถ๋ชจ๋ฅผ y๋ก ์ค์ ํด์ ํธ๋ฆฌ๋ฅผ ํฉ์น๊ณ
rank[rootX] += 1 // ํฉ์น ํธ๋ฆฌ์ ๋์ด 1 ์ฆ๊ฐ
}
}
}
- ํธ๋ฆฌ์ ๋์ด๋ฅผ ํตํด ์ต์ ํํ ์ฝ๋์ด๋ค.
- find์ ์๊ฐ ๋ณต์ก๋๋ ํธ๋ฆฌ์ ๋์ด์ ์ํด ๊ฒฐ์ ๋๋ค. ์ด๋, union ์ฐ์ฐํ ๋ ํญ์ ๋์ด๊ฐ ๋ฎ์ ํธ๋ฆฌ๋ฅผ ๋์ด๊ฐ ๋์ ํธ๋ฆฌ์ ๋ถ์ฌ์ ์๊ฐ ๋ณต์ก๋๋ฅผ ์ค์ผ ์ ์๋ค. ๋์ด๊ฐ ๋ฎ์ ํธ๋ฆฌ๋ฅผ ๋์ ํธ๋ฆฌ์ ๋ถ์ฌ์ผ ํฉ์ณ์ง ํธ๋ฆฌ์ ๋์ด๊ฐ ๋ ์ฆ๊ฐํ๋ค..
- ๋ฐ๋ผ์ ํธ๋ฆฌ์ ๋์ด๋ฅผ ๊ธฐ๋กํ rank ๋ฐฐ์ด์ ๋ณ๋๋ก ๋ง๋ค์ด๋๊ณ , ๋น๊ตํ๋ฉด์
3. PS ๋ฌธ์ ๋ชฉ๋ก
- [x] [๋ฐฑ์ค/๊ณจ5] ์งํฉ์ ํํ https://www.acmicpc.net/problem/1717
- [ ] [๋ฐฑ์ค/๊ณจ2] ์น๊ตฌ ๋คํธ์ํฌ https://www.acmicpc.net/problem/4195
- [ ] [๋ฐฑ์ค/๊ณจ4] ๊ฑฐ์ง๋ง https://www.acmicpc.net/problem/1043
- [ ] [๋ฐฑ์ค/๊ณจ3] ๊ฐ๊ตฌ๋ฆฌ ์ ํ https://www.acmicpc.net/problem/17619
- [ ] [๋ฐฑ์ค/๊ณจ4] ์ฌํ ๊ฐ์ https://www.acmicpc.net/problem/1976
- [ ] [ํ๋ก๊ทธ๋๋จธ์ค/Lv.4] ํธํ ๋ฐฉ ๋ฐฐ์ https://school.programmers.co.kr/learn/courses/30/lessons/64063
- [ ] https://www.acmicpc.net/workbook/view/6784