ํ์ด์ฌ ์๊ณ ๋ฆฌ์ฆ ๊ณต๋ถ - (5) ๊ธฐํ (์๋ก์ ์งํฉ, ์ ์ฅํธ๋ฆฌ, ์์์ ๋ ฌ)
๐์๋ก์ ์งํฉ
: ๊ณตํต ์์๊ฐ ์๋ ๋ ์งํฉ์ ์๋ฏธํจ
- ํฉ์งํฉ(Union) : ๋ ๊ฐ์ ์์๊ฐ ํฌํจ๋ ์งํฉ์ ํ๋์ ์งํฉ์ผ๋ก ํฉ์น๋ ์ฐ์ฐ
- ์ฐพ๊ธฐ(Find) : ํน์ ํ ์์๊ฐ ์ํ ์งํฉ์ด ์ด๋ค ์งํฉ์ธ์ง ์๋ ค์ฃผ๋ ์ฐ์ฐ
์๋ก์ ์งํฉ ์๋ฃ๊ตฌ์กฐ๋ ๋ ์ข ๋ฅ์ ์ฐ์ฐ์ ์ง์ํ๋ค.
ํฉ์งํฉ ์ฐ์ฐ์ด ํธํฅ๋๊ฒ ์ด๋ฃจ์ด์ง ๊ฒฝ์ฐ ๋นํจ์จ์ ์ผ๋ก ๋์
์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ๋ณต์ก๋ : O(V) (๋ชจ๋ ๋ ธ๋๋ฅผ ๋ค ํ์ธํด์ผ ํจ)
#ํน์ ์์๊ฐ ์ํ ์งํฉ์ ์ฐพ๊ธฐ
def find_parent(parent, x):
if parent[x] != x: #๋ฃจํธ ๋
ธ๋๋ฅผ ์ฐพ์ ๋๊น์ง ์ฌ๊ทํธ์ถ
return find_parent(parent, parent[x])
return x
# 2. ๊ฒฝ๋ก ์์ถ ๋ฐฉ๋ฒ์ผ๋ก findํจ์
def find_parent(parent, x):
if parent[x] != x: #๋ฃจํธ ๋
ธ๋๋ฅผ ์ฐพ์ ๋๊น์ง ์ฌ๊ทํธ์ถ
return find_parent(parent, parent[x])
return parent[x] #๋ถ๋ชจํ
์ด๋ธ ๊ฐ์ ๋ฐ๋ก ๊ฐฑ์
#๋ ์์๊ฐ ์ํ ์งํฉ์ ํฉ์น๊ธฐ
def union_parent(parent, a, b):
a = find_parent(parent, a)
b = find_parent(parent, b)
if a < b:
parent[b] = a
else:
parent[a] = b
#๋
ธ๋๊ฐ์, ๊ฐ์ ์
๋ ฅ๋ฐ๊ธฐ
v, e = map(int, input().split())
parent = [0] *(v+1)
for i in range(1, v+1):
parent[i] = i
for i in range(e):
a, b = map(int, input().split())
union_parent(parent, a, b)
# ๊ฐ ์์๊ฐ ์ํ ์งํฉ
for i in range(1, v+1):
print(find_parent(parent, i), end='')
# ๋ถ๋ชจ ํ
์ด๋ธ ๋ด์ฉ ์ถ๋ ฅ
for i in range(1, v+1):
print(parent[i], end='')
์๋ก์ ์งํฉ์ ์ด์ฉํ์ฌ ๋ฌด๋ฐฉํฅ ๊ทธ๋ํ ๋ด์์์ ์ฌ์ดํด์ ํ๋ณํ ์ ์๋ค.
(*๋ฐฉํฅ๊ทธ๋ํ ํ๋ณ์ DFS)
1. ๊ฐ ๊ฐ์ ์ ํ๋์ฉ ํ์ธํ๋ฉฐ ๋ ๋ ธ๋์ ๋ฃจํธ ๋ ธ๋๋ฅผ ํ์ธ, ๋ค๋ฅด๋ค๋ฉด ํฉ์งํฉ ์ฐ์ฐ ์ํ / ๊ฐ๋ค๋ฉด ์ฌ์ดํด์ด ๋ฐ์ํ ๊ฒ
2. ๊ทธ๋ํ์ ํฌํจ๋์ด ์๋ ๋ชจ๋ ๊ฐ์ ์ ๋ํ์ฌ 1๋ฒ ๋ฐ๋ณต
๋ฃจํธ ๋ ธ๋๊ฐ ๋ค ๊ฐ๋ค๋ฉด ์ฌ์ดํด์ด ๋ฐ์ํ ๊ฒ
for i in range(e):
a, b = map(int, input().split())
if find_parent(parent, a) == find_parent(parent, b):
cycle = True
break
else:
union_parent(parent, a, b)
๐์ ์ฅ ํธ๋ฆฌ
: ๊ทธ๋ํ์์ ๋ชจ๋ ๋ ธ๋๋ฅผ ํฌํจํ๋ฉด์ ์ฌ์ดํด์ด ์กด์ฌํ์ง ์๋ ๋ถ๋ถ ๊ทธ๋ํ๋ฅผ ์๋ฏธ
ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ
- ๋ํ์ ์ธ ์ต์ ์ ์ฅ ํธ๋ฆฌ ์๊ณ ๋ฆฌ์ฆ, ๊ทธ๋ฆฌ๋ ์๊ณ ๋ฆฌ์ฆ
1. ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๋น์ฉ์ ๋ฐ๋ผ ์ค๋ฆ์ฐจ์ ์ ๋ ฌ
2. ๊ฐ์ ์ ํ๋์ฉ ํ์ธํ๋ฉฐ ํ์ฌ์ ๊ฐ์ ์ด ์ฌ์ดํด์ ๋ฐ์์ํค๋์ง ํ์ธ ( ์ฌ์ดํด ๋ฐ์ X :์ต์ ์ ์ฅ ํธ๋ฆฌ์ ํฌํจ, ์ฌ์ดํด ๋ฐ์ : ํฌํจ X)
3. ๋ชจ๋ ๊ฐ์ ์ ๋ํด 2๋ฒ ๋ฐ๋ณต
- ๊ฐ์ ์ ๊ฐ์๊ฐ E๊ฐ์ผ ๋ ์๊ฐ๋ณต์ก๋ : O(ElogE)
# find_parent(parent, x), union_parent(parent, a, b) ํ์ฉ
# ํฌ๋ฃจ์ค์นผ ์๊ณ ๋ฆฌ์ฆ
for _ in range(e):
a, b, cost = map(int, input().split())
edges.append(cost, a, b)
edges.sort() #๋น์ฉ์ ๊ธฐ์ค์ผ๋ก ์ค๋ฆ์ฐจ์ ์ ๋ ฌ
for edge in edges:
cost, a, b = edge
# ์ฌ์ดํด ๋ฐ์ํ์ง ์๋๋ค๋ฉด ํฉ์น๊ธฐ, ๋น์ฉ ๋ํ๊ธฐ
if find_parent(parent, a) != find_parent(parent, b):
union_parent(parent, a, b)
result += cost
return result
๐์์ ์ ๋ ฌ
: ์ฌ์ดํด์ด ์๋ ๋ฐฉํฅ ๊ทธ๋ํ์ ๋ชจ๋ ๋ ธ๋๋ฅผ ๋ฐฉํฅ์ฑ์ ๊ฑฐ์ค๋ฅด์ง ์๋๋ก ์์๋๋ก ๋์ดํ๋ ๊ฒ์ ์๋ฏธ
- ํ๋ฅผ ์ด์ฉํ๋ ์์ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ
1. ์ง์ ์ฐจ์๊ฐ 0์ธ ๋ชจ๋ ๋ ธ๋๋ฅผ ํ์ ๋ฃ๋๋ค.
1-1. ํ์์ ์์๋ฅผ ๊บผ๋ด ํด๋น ๋ ธ๋์์ ๋๊ฐ๋ ๊ฐ์ ๊ทธ๋ํ๋ฅผ ์ ๊ฑฐํ๋ค.
1-2. ์๋กญ๊ฒ ์ง์ ์ฐจ์๊ฐ 0์ด ๋ ๋ ธ๋๋ฅผ ํ์ ๋ฃ๋๋ค.
2. ํ๊ฐ ๋น ๋๊น์ง ๋ฐ๋ณต
*์ง์ ์ฐจ์: ํน์ ํ ๋ ธ๋๋ก ๋ค์ด์ค๋ ๊ฐ์ ์ ๊ฐ์
*์ง์ถ์ฐจ์: ํน์ ํ ๋ ธ๋์์ ๋๊ฐ๋ ๊ฐ์ ์ ๊ฐ์
- ์ฌ๋ฌ ๊ฐ์ง ๋ต์ด ์กด์ฌํ ์ ์๋ค.
- ๋ชจ๋ ์์๋ฅผ ๋ฐฉ๋ฌธํ๊ธฐ ์ ์ ํ๊ฐ ๋น๋ค๋ฉด ์ฌ์ดํด์ด ์กด์ฌํ๋ค๊ณ ํ๋จํ ์ ์๋ค.
- ์คํ์ผ๋ก ์ด์ฉํ ์๋ ์๋ค.
- ์๊ฐ ๋ณต์ก๋ : O(V+E)
from collections import deque
v, e = map(int, input().split())
indegree = [0]*(v+1) # ์ง์
์ฐจ์ ์ด๊ธฐํ
graph = [[] for i in range(v+1)]
for _ in range(e): # ๊ฐ์ ์ ๋ณด ์
๋ ฅ๋ฐ๊ธฐ
a, b = map(int, input().split())
graph[a].append(b)
indegree[b] += 1
# ์์์ ๋ ฌ ํจ์
def topology_sort():
result = []
q = deque()
for i in range(1, v+1):
if indegree[i] == 0:
q.append(i)
# ํ๊ฐ ๋น ๋๊น์ง ๋ฐ๋ณต
while q:
now = q.popleft()
result.append(now)
for i in graph[now]:
indegree[i] -= 1
if indegree[i] == 0:
q.append(i)
for i in result:
print(i, end='')
topology_sort()