Minimum Spanning Tree

์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ (MST)

MST Algorithms ์˜ ์ข…๋ฅ˜

  1. Prim Algorithm - ์ •์ ์„ ์„ ํƒ

  2. KRUSKAL Algorithm - ๊ฐ„์„ ์„ ์„ ํƒ๋žจ

๊ทธ๋ž˜ํ”„์—์„œ ์ตœ์†Œ ๋น„์šฉ ๋ฌธ์ œ

  1. ๋ชจ๋“  ์ •์ ์„ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฐ„์„ ๋“ค์˜ ๊ฐ€์ค‘์น˜์˜ ํ•ฉ์ด ์ตœ์†Œ๊ฐ€ ๋˜๋Š” Tree

  2. ๋‘ ์ •์  ์‚ฌ์ด์˜ ์ตœ์†Œ ๋น„์šฉ์˜ ๊ฒฝ๋กœ ์ฐพ๊ธฐ

์‹ ์žฅ ํŠธ๋ฆฌ (Spanning Tree)

: n๊ฐœ์˜ ์ •์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฌด๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„์—์„œ n๊ฐœ์˜ ์ •์ ๊ณผ n-1๊ฐœ์˜ ๊ฐ„์„ ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ํŠธ๋ฆฌ

์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ (Mininum Spanning Tree)

: ๋ฌด๋ฐฉํ–ฅ ๊ฐ€์ค‘์น˜ ๊ทธ๋ž˜ํ”„์—์„œ ์‹ ์žฅํŠธ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐ„์„ ๋“ค์˜ ๊ฐ€์ค‘์น˜์˜ ํ•ฉ์ด ์ตœ์†Œ์ธ ์‹ ์žฅํŠธ๋ฆฌ

MST ํ‘œํ˜„

Graph ํ‘œํ˜„

  • ๊ทธ๋ž˜ํ”„

  • ๊ฐ„์„ ๋“ค์˜ ๋ฐฐ์—ด

  • ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ

  • ๋ถ€๋ชจ ์ž์‹ ๊ด€๊ณ„์™€ ๊ฐ€์ค‘์น˜์— ๋Œ€ํ•œ ๋ฐฐ์—ด

    • Tree๋กœ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋‹ค

Prim Algorithm

  • ํ•˜๋‚˜์˜ ์ •์ ์—์„œ ์—ฐ๊ฒฐ๋œ ๊ฐ„์„ ๋“ค ์ค‘์— ํ•˜๋‚˜์”ฉ ์„ ํƒํ•˜๋ฉด์„œ MST๋ฅผ ๋งŒ๋“ค์–ด ๊ฐ€๋Š” ๋ฐฉ์‹

    1. ์ž„์˜์˜ ์ •์ ์„ ํ•˜๋‚˜ ์„ ํƒํ•ด์„œ ์‹œ์ž‘

    2. ์„ ํƒํ•œ ์ •์ ๊ณผ ์ธ์ ‘ํ•˜๋Š” ์ •์ ๋“ค ์ค‘์˜ ์ตœ์†Œ ๋น„์šฉ์˜ ๊ฐ„์„ ์ด ์กด์žฌํ•˜๋Š” ์ •์ ์„ ์„ ํƒ

    3. ๋ชจ๋“  ์ €์ ์ด ์„ ํƒ๋  ๋•Œ ๊นŒ์ง€ 1,2 ๊ณผ์ • ๋ฐ˜๋ณต

  • ์„œ๋กœ์†Œ(์ƒํ˜ธ ๋ฐฐํƒ€)์ธ 2๊ฐœ์˜ ์ง‘ํ•ฉ(2 disjoint-sets) ์ •๋ณด๋ฅผ ์œ ์ง€

    • ํŠธ๋ฆฌ ์ •์ ๋“ค (tree vertices)

      • MST๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์„ ํƒ๋œ ์ •์ ๋“ค

    • ๋น„ํŠธ๋ฆฌ ์ •์ ๋“ค (nontree vertices)

      • ์„ ํƒ ๋˜์ง€ ์•Š์€ ์ •์ ๋“ค

ex)

MST

"""
MST  + ์ธ์ ‘ํ–‰๋ ฌ

7 11
0 5 60
0 1 32
0 2 31
0 6 51
1 2 21
2 4 46
2 6 25
3 4 34
3 5 18
4 5 40
4 6 51

์‹œ์ž‘์ •์  ๋์ •์  ๊ฐ€์ค‘์น˜

๊ฒฐ๊ณผ
[0, 21, 31, 34, 46, 18, 25]
175
"""

V, E = map(int, input().split())
adj = [[0] * V for _ in range(V)]

for i in range(E):
    s, e, c = map(int, input().split())
    adj[s][e] = c
    adj[e][s] = c # ๋ฌด๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„๋ผ์„œ

# for row in adj:
#     print(row)

# key, p(parent), mst ์ค€๋น„
INF = float('inf')
key = [INF] *V # key๋Š” ๋ฌดํ•œ๋Œ€๋กœ ์ดˆ๊ธฐํ™”
p = [-1] * V   # p(parent)๋Š” -1๋กœ ์ดˆ๊ธฐํ™”
mst = [False] * V

# ์‹œ์ž‘์  ์„ ํƒ : 0๋ฒˆ ์„ ํƒ
key[0] = 0
cnt = 0
result = 0
while cnt < V:
    # ์•„์ง mst๊ฐ€ ์•„๋‹ˆ๊ณ , key๊ฐ€ ์ตœ์†Œ์ธ ์ •์  ์„ ํƒ : u
    MIN = INF
    u = -1
    for i in range(V):
        if not mst[i] and key[i] <MIN:
            MIN = key[i]
            u = i
    # u๋ฅผ mst๋กœ ์„ ํƒ
    mst[u] = True
    result += MIN
    cnt+=1
    # key ๊ฐ’์„ ๊ฐฑ์‹ 
    # u์— ์ธ์ ‘ํ•˜๊ณ , ์•„์ง mst๊ฐ€ ์•„๋‹Œ ์ •์  w์—์„œ key[w] > u - w ๊ฐ€์ค‘์น˜  ์ด๋ฉด ๊ฐฑ์‹ !
    for w in range(V):
        if adj[u][w] > 0 and not mst[w] and key[w] > adj[u][w]:
            key[w] = adj[u][w]
            p[w] = u

print(key) # [0, 21, 31, 34, 46, 18, 25]
print(p) # [-1, 2, 0, 4, 2, 3, 2]
print(result) # 175

ex)

Mst - prim algorithm

# Prim Algorithm
# : ํ•˜๋‚˜์˜ ์ •์ ์—์„œ ์—ฐ๊ฒฐ๋œ ๊ฐ„์„ ๋“ค ์ค‘์— ํ•˜๋‚˜์”ฉ ์„ ํƒ ํ•˜๋ฉด์„œ MST๋ฅผ ๋งŒ๋“ค์–ด ๊ฐ€๋Š” ๋ฐฉ์‹

# ์šฐ์„ ์ˆœ์œ„ ํ ํ™œ์šฉํ•˜๊ธฐ -> ์ด์ง„ํž™ -> heapq
import heapq

"""
MST  + ์ธ์ ‘ํ–‰๋ ฌ

7 11
0 5 60
0 1 32
0 2 31
0 6 51
1 2 21
2 4 46
2 6 25
3 4 34
3 5 18
4 5 40
4 6 51

์‹œ์ž‘์ •์  ๋์ •์  ๊ฐ€์ค‘์น˜

๊ฒฐ๊ณผ
[0, 21, 31, 34, 46, 18, 25]
175
"""

V, E = map(int, input().split())
adj = {i: [] for i in range(V)}
for i in range(E):
    s, e, c = map(int, input().split())
    adj[s].append([e,c])
    adj[e].append([s,c]) #๋ฌด๋ฐฉํ–ฅ์ด๋ผ์„œ
# print(adj)

# key, mst, ์šฐ์„ ์ˆœ์œ„ ํ ์ค€๋น„
INF = float('inf')
key = [INF] * V
mst = [False] * V
pq = []
# ์‹œ์ž‘ ์ •์  ์„ ํƒ : 0
key[0] = 0
# ํ์— ์‹œ์ž‘ ์ •์ ์„ ๋„ฃ์Œ => (key, ์ •์  index) ๋ฌถ์–ด์„œ ๋„ฃ๊ธฐ
# ์šฐ์„ ์ˆœ์œ„ ํ => ์ด์ง„ํž™ => heapq ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ
heapq.heappush(pq, (0,0)) # heqppush(๋ฐฐ์—ด ์ •๋ณด, ์–ด๋–ค ์›์†Œ ๋„ฃ์„ ์ง€) : heap์˜ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ํ•˜๋‚˜์˜ ์›์†Œ๋ฅผ ๋„ฃ์–ด์คŒ
                    # ์šฐ์„ ์ˆœ์œ„ํ -> ์›์†Œ์˜ ์ฒซ๋ฒˆ์งธ ์š”์†Œ -> key๋ฅผ ์šฐ์„ ์ˆœ์œ„๋กœ
result = 0
while pq:
    # ์ตœ์†Œ๊ฐ’ ์ฐพ๊ธฐ
    k, node = heapq.heappop(pq) #๋‚ด๊ฐ€ ๊ฐ–๊ณ ์žˆ๋Š” heapq์—์„œ ์ตœ์†Œ๊ฐ’์„ popํ•ด์คŒ
    if mst[node]: continue # ๊ฐฑ์‹  ํ•  ๋•Œ ํ•„์š”ํ–ˆ๋˜ ์ •๋ณด๋Š” skipํ•˜๊ธฐ
    # mst๋กœ ์„ ํƒ
    mst[node] = True
    result += k
    # key๊ฐ’ ๊ฐฑ์‹  => key๋ฐฐ์—ด / ํ
    for destination, weight in adj[node]:
        if not mst[destination] and key[destination] > weight:
            key[destination] = weight
            # ํ ๊ฐฑ์‹  => ์ƒˆ๋กœ์šด (key, ์ •์ ) ์‚ฝ์ž… => ํ•„์š”์—†๋Š” ์›์†Œ๋Š” skip
            heapq.heappush(pq, (key[destination], destination))

print(result) # 175

KRUSKAL Algorithm

: ๊ฐ„์„ ์„ ํ•˜๋‚˜์”ฉ ์„ ํƒํ•ด์„œ MST๋ฅผ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

  1. ์ตœ์ดˆ, ๋ชจ๋“  ๊ฐ„์„ ์„ ๊ฐ€์ค‘์น˜์— ๋”ฐ๋ผ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ

  2. ๊ฐ€์ค‘์น˜๊ฐ€ ๊ฐ€์žฅ ๋‚ฎ์€ ๊ฐ„์„ ๋ถ€ํ„ฐ ์„ ํƒํ•˜๋ฉด์„œ ํŠธ๋ฆฌ๋ฅผ ์ฆ๊ฐ€์‹œํ‚ด

    • ์‚ฌ์ดํด์ด ์กด์žฌํ•˜๋ฉด ๋‹ค์Œ์œผ๋กœ ๊ฐ€์ค‘์น˜๊ฐ€ ๋‚ฎ์€ ๊ฐ„์„  ์„ ํƒ

      • ์‚ฌ์ดํด์€ ์„ ํƒํ•˜์ง€ ์•Š๋Š”๋‹ค!

        • ์‚ฌ์ดํด์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋กœ ๊ฐ€๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋Œ์•„์„œ ๊ฐ€๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ

    • ์‚ฌ์ดํด์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฒ•

      • ์ •์ ์˜ ๋Œ€ํ‘œ์ž๊ฐ€ ๊ฐ™์œผ๋ฉด ์‚ฌ์ดํด์ด ์žˆ๋‹ค๋Š” ๊ฒƒ!

  3. n-1๊ฐœ์˜ ๊ฐ„์„ ์ด ์„ ํƒ๋  ๋•Œ ๊นŒ์ง€ 2๋ฅผ ๋ฐ˜๋ณต

ex)

kruskal

"""
์˜ˆ์ œ

7 11
0 5 60
0 1 32
0 2 31
0 6 51
1 2 21
2 4 46
2 6 25
3 4 34
3 5 18
4 5 40
4 6 51

"""

def make_set(x):
    p[x] = x

def find_set(x):
    if p[x] == x:
        return x
    else:
        p[x] = find_set(p[x])
        return p[x]

def union(x,y):
    px = find_set(x)
    py = find_set(y)
    if rank[px] > rank[py]:
        p[py] = px
    else:
        p[px] = py
        if rank[px] == rank[py]:
            rank[py] += 1

V, E = map(int, input().split())
edges = [ list(map(int, input().split()))for _ in range(E)]

# ๊ฐ„์„ ์„ ๊ฐ„์„  ๊ฐ€์ค‘์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ
edges.sort(key=lambda x: x[2]) # () ์•”์— ๊ธฐ์ค€์ด ๋“ค์–ด๊ฐ

# make_set : ๋ชจ๋“  ์ •์ ์— ๋Œ€ํ•ด ์ง‘ํ•ฉ ์ƒ์„ฑ
p = [0] * V
rank = [0] * V
for i in range(V):
    make_set(i)

cnt = 0
result = 0
mst = []
# ๋ชจ๋“  ๊ฐ„์„ ์— ๋Œ€ํ•ด์„œ ๋ฐ˜๋ณต -> V-1๊ฐœ์˜ ๊ฐ„์„ ์ด ์„ ํƒ๋  ๋•Œ ๊นŒ์ง€
for i in range(E):
    s, e, c = edges[i][0], edges[i][1], edges[i][2]
    # ์‚ฌ์ดํด์ด๋ฉด skip : ์ฑ„ํƒํ•˜๋ ค๋Š” ๋‘ ์ •์ ์ด ใ……๋กœ ๊ฐ™์€ ์ง‘ํ•ฉ์ด๋ฉด skip  => find_set ์ด์šฉ
    if find_set(s) == find_set(e):
        continue
    # ๊ฐ„์„  ์„ ํƒ
    result += c
    mst.append(edges[i])
    # => mst์— ๊ฐ„์„  ์ •๋ณด ๋”ํ•˜๊ธฐ / ๋‘ ์ •์ ์„ ํ•ฉ์นœ๋‹ค  => Union
    union(s,e)
    cnt +=1
    if cnt == V-1:
        break

print(result) # 175
print(mst) #[[3, 5, 18], [1, 2, 21], [2, 6, 25], [0, 2, 31], [3, 4, 34], [2, 4, 46]]

Last updated

Was this helpful?