Union-Find
๊ฐ๋
- ๊ทธ๋ํ์์ ๋ ๋ ธ๋๊ฐ ๊ฐ์ ๊ทธ๋ํ์ ์ํ๋์ง(์ฐ๊ฒฐ๋์ด ์๋์ง)๋ฅผ ํ๋ณ
- ์ํธ ๋ฐฐํ์ ์งํฉ(Disjoint Set)์ด๋ผ๊ณ ๋ ํจ
- ์๊ฐ ๋ณต์ก๋
- ๋ํ ๋
ธ๋(๋ฃจํธ) ์ฐพ๊ธฐ
find: $O( \alpha(N))$ โ ์ค์ ์์ ๊ฑฐ์ $O(N)$ - ์งํฉ ํฉ์น๊ธฐ
union: $O( \alpha(N))$ โ ์ค์ ์์ ๊ฑฐ์ $O(N)$
- ๋ํ ๋
ธ๋(๋ฃจํธ) ์ฐพ๊ธฐ
์ ์ฒด ์ฝ๋
def find(a):
if parent[a] != a: parent[a] = find(parent[a])
return parent[a]
def union(a,b):
pa, pb = find(a), find(b)
if a < b : parent[b] = parent[a]
else : parent[a] = parent[b]
# ๊ทธ๋ํ๊ฐ ์ฃผ์ด์ก๋ค๋ฉด
graph = [] #<- list in list
parent = [] #<- ๋
ธ๋ ์๋งํผ
result = set()
for i in range(len(graph)):
for j in range(len(graph[i]):
union(graph[i], graph[j])
set.add(parent[i])
Union-Find ๊ตฌ์ฑํ๋ ํจ์๋ค
find : ๋ํ ๋
ธ๋(root) ์ฐพ๊ธฐ
def find(a, b):
if parent[a] != a: parent[a] = find(parent[a])
return parent[a]
if parent[a] != aโ ๋ด ๋ถ๋ชจ๊ฐ ๋ด๊ฐ ์๋ ๋ = ๋ ์์ ์ด root๊ฐ ์๋๋- ๊ณ์ ๋ถ๋ชจ ํ๊ณ ์ฌ๋ผ๊ฐ๋ฉด์ ์งํฉ์ ๋ํ(root)๋ฅผ ์ฐพ์
union : ์งํฉ ํฉ์น๊ธฐ
def union(a,b):
pa, pb = find(a), find(b)
if a == b : return
elif a < b : parent[b] = parent[a]
else : parent[a] = parent[b]
if a == bโ ๋ ๊ฐ์ ๋ ธ๋๊ฐ ๊ฐ์ ์งํฉ์ ์ํจ- ๋ค์ unionํ ํ์ ์์ผ๋ฏ๋ก return
elif a < b&else: union ์์ ํ์ํจ- ๋ํ์๋ฅผ ๋ ์์ ๋ ธ๋ ๊ฐ์ผ๋ก ์ค์ ํ๋ ์กฐ๊ฑด
- ๊ทธ๋ฅ
a != b์ผ ๋a๋b์ค ํ๋๋ก parent ํต์ผ ์์ผ์ค๋ ์๊ด์๊ธด ํจ - ๊ทผ๋ฐ ๋ํ์๋ฅผ ์์ ์๋ก ๋๋ ๊ฒ ๋ ์ค์ฉ์
- ์ ๋ ฌ๋ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ โ ํด์์ด ์ฌ์
- ์ฌ์ดํด ํ๋ณ ์ ์์ ์ ์ธ ๊ตฌ์กฐ
- ํธ๋ฆฌ ๊น์ด ์ํ
Union-Find๋ฅผ ๊ฐ์ ํด๋ณด์!
Path Compression : ๊ฒฝ๋ก ์์ถ
- find ํ ๋ ๊ฒธ์ฌ๊ฒธ์ฌ ํธ๋ฆฌ ๋์ด๋ ํํํ๊ฒ ํ์
- find๋ก root ์ฐพ์ ํ์ ์ด root๋ฅผ parent์ ์ ์ฅํด์ ๋ค์์ findํ ๋๋ ๋ฐ๋ก ์ฐพ์ ์ ์๊ฒ ํจ
- ๋ํ๊ฐ ์๋ ๋ ธ๋๋ฅผ parent๋ก ์ฐ๊ฒฐํ๋๊ฒ ์๋๋ผ root์ ์ง์ ์ฐ๊ฒฐํ์
def find(a):
if parent[a] != a: parent[a] = find(parent[a]) # ๊ฒฝ๋ก ์์ถ
return parent[a]
Union by Rank : ๋ญํฌ ๊ฐ๋ ์ฌ์ฉํ๊ธฐ
- Rank : ๊ฐ ์งํฉ์ ํธ๋ฆฌ ํฌ๊ธฐ๋ฅผ ๋น๊ตํ๊ธฐ ์ํ ์๋ก ํธ๋ฆฌ์ ๋์ด๋ฅผ ๋งํจ
- ๋ ๊ฐ์ ์งํฉ์ Unionํ ๋ ๋์ด๊ฐ ๋ ์์ ํธ๋ฆฌ๋ฅผ ํฐ ํธ๋ฆฌ์ ์์์ผ๋ก ๋ฃ์ด์ฃผ๋ ๋ฐฉ์
- ์์ ํธ๋ฆฌ๋ฅผ ํฐ ํธ๋ฆฌ์ ๋ถ์์ ๋ ํธ๋ฆฌ ๋์ด๊ฐ ๋ ์ฆ๊ฐ
- ์์ ํธ๋ฆฌ rank :
s, ํฐ ํธ๋ฆฌ rank :bโs โค b - ์์ ํธ๋ฆฌ๋ฅผ ์ง์ด๋ฃ์์ ๋ ํธ๋ฆฌ rank :
max(s+1, b)โs+1orb - ํฐ ํธ๋ฆฌ๋ฅผ ์ง์ด๋ฃ์์ ๋ ํธ๋ฆฌ rank :
max(s, b+1)โb+1
- ์์ ํธ๋ฆฌ rank :
- ๊ทธ๋์
findํ ๋ parent ๋ ธ๋ ํ๊ณ ๊ฐ๋ ํ์๊ฐ ์ ์ด ๋ ํจ์จ์
- ์์ ํธ๋ฆฌ๋ฅผ ํฐ ํธ๋ฆฌ์ ๋ถ์์ ๋ ํธ๋ฆฌ ๋์ด๊ฐ ๋ ์ฆ๊ฐ
def union(a, b):
pa, pb = find(a), find(b)
if pa == pb: return
# Union by Rank
if rank[pa] < rank[pb]:
parent[pa] = pb
elif rank[pa] > rank[pb]:
parent[pb] = pa
else:
parent[pb] = pa
rank[pa] += 1
MST : ํฌ๋ฃจ์ค์นผ & ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ
: ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ๊ณผ ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ์ MST๋ฅผ ๋ง๋๋ ์๊ณ ๋ฆฌ์ฆ
MST (Minimum Spanning Tree)
- ๊ฐ๋
- ๋ชจ๋ ์ ์ ์ ์ฐ๊ฒฐํ๋ฉด์
- Cycle ์ด ์๊ณ
- ๊ฐ์ ์ ์ด ๊ฐ์ค์น๊ฐ ์ต์์ธ ๊ทธ๋ํ
- ์ด๋ค ๊ทธ๋ํ๊ฐ ์์ ๋,
๋ชจ๋ ๋ ธ๋๋ฅผ ์ฐ๊ฒฐํ ์ ์๋ ๊ฐ์ ์ ๊ฐ์ค์น ํฉ์ ์ต์๋ก ํ๋ ๊ฒฝ์ฐ๋ฅผ ๊ตฌํ๊ณ ์ ํ ๋ MST๋ฅผ ๋ง๋ฌ - ์ด๋ฐ MST๋ฅผ ๋ง๋๋๋ฐ ํฌ๋ฃจ์ค์นผ ํน์ ํ๋ฆผ์ ****์ฌ์ฉ
Kruskal ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ
๊ฐ์ ์ ๊ธฐ์ค์ผ๋ก MST๋ฅผ ๋ง๋ค์ด๊ฐ๋ ์๊ณ ๋ฆฌ์ฆ
Union-Find ์๊ณ ๋ฆฌ์ฆ์ ํ์ฉํด์ ๊ตฌํ
๋์ ์์
edges = [(1, 0, 1), (3, 1, 2), ... ] # ๊ฐ์ ์ ๋ณด (์ฐ๊ฒฐ ๋ ธ๋ A, ์ฐ๊ฒฐ ๋ ธ๋ B, weight) parent = [i for i in range(6)] def find(x): if parent[x] != x: parent[x] = find(parent[x]) return parent[x] def union(x, y): x_root = find(x) y_root = find(y) if x_root != y_root: parent[y_root] = x_root return True ****return False edges.sort() # ๊ฐ์ค์น ๊ธฐ์ค ์ค๋ฆ์ฐจ์ mst_weight = 0 edge_cnt = 0 for w, a, b in edges: if union(a, b): edge_cnt += 1 mst_weight += w if edge_cnt == len(parent)-1 : break print("Kruskal MST ์ด ๊ฐ์ค์น:", mst_weight)- ๊ฐ์ ์ ๋ณด๋ฅผ ๋ฐฐ์ด์ ์ ์ฅํ๊ณ ๊ฐ์ค์น๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค๋ฆ์ฐจ์ ์ ๋ ฌ
- ๊ฐ์ค์น๊ฐ ์์ ๊ฐ์ ๋ถํฐ ํ๋ ์ฉ ๋ฝ์์
- ๊ฐ์ ๊ณผ ์ฐ๊ฒฐ๋ ๋
ธ๋
unionํ์ ๋- ์ด๋ฏธ ์ฐ๊ฒฐ๋์ด์์ผ๋ฉด โ
continue- ์ด๋ฏธ ์ฐ๊ฒฐ๋์ด์๋ ๋ ธ๋์ ๋ํ ๊ฐ์ ์ ๋ ์ถ๊ฐํ ๊ฒฝ์ฐ cycle ์๊น
- ์์ง ์ฐ๊ฒฐ ์๋์ด ์์ผ๋ฉด โ ์ ํ :
mst_weight๊ฐ์ ๋ํ๊ธฐ
- ์ด๋ฏธ ์ฐ๊ฒฐ๋์ด์์ผ๋ฉด โ
- ์ ํํ ๊ฐ์ ์ ๊ฐ์๊ฐ
๋ ธ๋ ๊ฐ์-1์ด๋ฉด ์ข ๋ฃ๋ ธ๋ ๊ฐ์-1๊ฐ๋ฉด ๋ชจ๋ ๋ ธ๋ ์ฐ๊ฒฐ ๊ฐ๋ฅํจ
์๊ฐ ๋ณต์ก๋ : $O(E log E)$ โ ๊ฐ์ ์ด ๋ง์ง ์์ ๋ ํ์ฉํ๋ฉด ์ข์ ์๊ณ ๋ฆฌ
Prim ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ
๋ ธ๋๋ฅผ ๊ธฐ์ค์ผ๋ก MST๋ฅผ ๋ง๋๋ ์๊ณ ๋ฆฌ์ฆ
BFS๋ก ๋ฐฉ๋ฌธํ๋ฉฐ ๊ฐ์ ์ ๊ธฐ์ค์ผ๋ก ์ ์ฅ๋๋ ์ฐ์ ์์ Queue์ ๋ ธ๋๋ฅผ ์ถ๊ฐํ๋ฉด์ ํ์
๋์ ์์
import heapq # ์ธ์ ๋ฆฌ์คํธ ๊ทธ๋ํ graph = { 0: [(1, 1), (3, 4)], 1: [(0, 1), (2, 3), (4, 2)], 2: [(1, 3), (5, 5)], 3: [(0, 4), (4, 6)], 4: [(1, 2), (3, 6), (5, 7)], 5: [(2, 5), (4, 7)] } visited = [False] * 6 heap = [(0, 0)] # (๊ฐ์ค์น, ์์ ์ ์ ) mst_weight = 0 while heap: weight, node = heapq.heappop(heap) if visited[node]: continue visited[node] = True mst_weight += weight for w, neighbor in graph[node]: if not visited[neighbor]: heapq.heappush(heap, (w, neighbor)) print("Prim MST ์ด ๊ฐ์ค์น:", mst_weight)- ์์์ ์ ์ ์์ ์์ (์์์ ์ฐ์ ์์ Queue์ ์ถ๊ฐ)
- ํ์ฌ ํธ๋ฆฌ์ ์ธ์ ํ ๊ฐ์ ์ค ๊ฐ์ฅ ์งง์ ๊ฒ ์ ํ
- ์ฐ์ ์์ Queue์์ pop
- popํ ๋
ธ๋์ ๊ฐ์ค์น๋ฅผ
mst_weight์ ๋ํจ
- ์์ง ๋ฐฉ๋ฌธํ์ง ์์ ์ ์ ์ ์ถ๊ฐํ๊ณ 1~3 ๋ฐ๋ณต
- pop ํ ๋ ธ๋์ ์ฐ๊ฒฐ๋ ๊ฐ์ ์ ๊ธฐ์ค์ผ๋ก ์๋ก ๋ฐฉ๋ฌธํ๋ ๋ ธ๋์ ๊ฐ์ค์น๋ฅผ Queue์ ์ถ๊ฐ
- ๋ชจ๋ ์ ์ ์ ๋ฐฉ๋ฌธํ ๋ ๊น์ง
์๊ฐ ๋ณต์ก๋ : $O(E log V)$ โ ๊ฐ์ ์ด ๋ง๊ฑฐ๋ ๋ ธ๋ ์๊ฐ ์ ์ ๋ ์ ์ฉํ ์๊ณ ๋ฆฌ์ฆ
'STUDY LOG > ๐ฉ๐ปโ๐ป โฐ ์ฝ๋ฉ ํ ์คํธ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| ์๊ณ ๋ฆฌ์ฆ ์คํฐ๋ Segment Tree (0) | 2025.04.14 |
|---|---|
| ์๊ณ ๋ฆฌ์ฆ ์คํฐ๋ Recap (DP &Dijkstra) (0) | 2025.03.13 |
| Java ์๊ณ ๋ฆฌ์ฆ ์คํฐ๋ DnC & Hashing (0) | 2025.02.27 |
| Java ์๊ณ ๋ฆฌ์ฆ ์คํฐ๋ DP & Heap (0) | 2025.02.21 |
| Java ์๊ณ ๋ฆฌ์ฆ ์คํฐ๋ Graph & Tree (1) | 2025.02.13 |