Updated:

๐ŸŽกย Spanning Tree

๊ทธ๋ž˜ํ”„ ๋‚ด๋ถ€์— ํฌํ•จ๋œ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ํŠธ๋ฆฌ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ๋ชจ๋“  ์ •์ ์„ ํฌํ•จํ•˜๊ธด ํ•˜์ง€๋งŒ ๊ทผ๋ณธ์€ ํŠธ๋ฆฌ๋ผ์„œ ์‚ฌ์ดํด์ด ๋ฐœ์ƒํ•˜๋ฉด ์•ˆ๋˜๋ฉฐ, ์ตœ์†Œ์˜ ๊ฐ„์„ ์„ ์‚ฌ์šฉํ•ด ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•ด์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ Spanning Tree ์˜ ๊ฐ„์„  ๊ฐœ์ˆ˜๋Š” ๋…ธ๋“œ ๊ฐœ์ˆ˜-1์— ํ•ด๋‹นํ•œ๋‹ค.

๐Ÿ’ตย Minimum Spanning Tree

๊ทธ๋ž˜ํ”„ ์ƒ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ Spanning Tree ์ค‘์—์„œ ๊ฐ„์„ ๋“ค์˜ ๊ฐ€์ค‘์น˜ ํ•ฉ์ด ์ตœ์†Œ์ธ ํŠธ๋ฆฌ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. MST๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋Œ€ํ‘œ์ ์œผ๋กœ Kruskal, Prim์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์žˆ๋‹ค. ์ „์ž์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(ElogE), ํ›„์ž๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ O(N^2)์ด๋ผ์„œ ๋…ธ๋“œ์— ๋น„ํ•ด ๊ฐ„์„  ๊ฐœ์ˆ˜๊ฐ€ ์ ์€ ํฌ์†Œ ๊ทธ๋ž˜ํ”„์˜ ๊ฒฝ์šฐ๋Š” Kruskal์„, ๋…ธ๋“œ์— ๋น„ํ•ด ๊ฐ„์„ ์ด ๋งŽ์€ ๋ฐ€์ง‘ ๊ทธ๋ž˜ํ”„์˜ ๊ฒฝ์šฐ๋Š” Prim์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์‹œ๊ฐ„ ๋ณต์žก๋„ ์ธก๋ฉด์—์„œ ์œ ๋ฆฌํ•˜๋‹ค. ํ•œํŽธ, Prim์€ ๊ตฌํ˜„์‹œ์— ์„ ํƒํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์— ๋”ฐ๋ผ์„œ ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ฐœ๋ณ„ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•œ ์„ค๋ช…์—์„œ ๋‹ค๋ฃจ๋„๋ก ํ•˜๊ฒ ๋‹ค.

๐Ÿƒย Kruskal Algorithm (๊ฐ„์„  ์„ ํƒ)

๊ทธ๋ฆฌ๋””ํ•˜๊ฒŒ ๊ทธ๋ž˜ํ”„์˜ ๋ชจ๋“  ์ •์ ์„ ์ตœ์†Œ ๋น„์šฉ์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ๊ตฌ์ฒด์ ์œผ๋กœ๋Š” ๊ฐœ๋ณ„ ์‹œ์ ์—์„œ ์‚ฌ์ดํด์„ ์ด๋ฃจ์ง€ ์•Š์œผ๋ฉด์„œ ์ตœ์†Œ ๋น„์šฉ์ธ ๊ฐ„์„ ์„ ๊ฒฝ๋กœ๋กœ ์„ ํƒํ•œ๋‹ค. ๊ทธ๋ฆฌ๋””๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์ „ ๊ฒฐ๊ณผ, ๋ฏธ๋ž˜ ๊ฒฐ๊ณผ๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ณ  ํ˜„์žฌ ์ตœ์†Œ ๋น„์šฉ์ด ๋˜๋Š” ๊ฐ„์„ ๋งŒ์„ ์„ ํƒํ•œ๋‹ค. ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ตฌ์ฒด์ ์ธ ๋™์ž‘ ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • 1) ๊ทธ๋ž˜ํ”„์˜ ๊ฐ„์„ ๋“ค์„ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ, ๊ฐ€์ค‘์น˜ ๊ธฐ์ค€
  • 2) ์‚ฌ์ดํด์„ ๋ฐœ์ƒ์‹œํ‚ค๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜๋ฉด์„œ ์ˆœ์„œ๋Œ€๋กœ ์„ ํƒ
    • ๊ฐ€์žฅ ๋‚ฎ์€ ๊ฐ€์ค‘์น˜๋ถ€ํ„ฐ ์ ‘๊ทผํ•ด ์ฒดํฌ
    • ์‚ฌ์ดํด ๋ฐœ์ƒ X๋ผ๋ฉด ์„ ํƒ
  • 3) ์„ ํƒํ•œ ๊ฐ„์„ ์„ MST์ง‘ํ•ฉ์— ์ถ”๊ฐ€

์‚ฌ์ดํด์„ ๋ฐœ์ƒ์‹œํ‚ค๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜๋Š” ๋ถ€๋ถ„์ด ๊ตฌํ˜„ํ•  ๋•Œ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ๋Š”๋ฐ, Union-Find ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋„์ž…ํ•˜๋ฉด ์ˆ˜์›”ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. Union-Find๋ฅผ ๋„์ž…ํ•œ Kruskal Algorithm์„ Python ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

""" kruskal algorithm example: baekjoon 1043 """

import sys

def find(arr: list, x: int) -> int:
    """ method for finding root node """
    if arr[x] != x:
        arr[x] = find(arr, arr[x])
    return arr[x]

def union(arr: list, x: int, y: int):
    """ method for union-find """
    x = find(arr, x)
    y = find(arr, y)
    if x < y:
        arr[y] = x
    else:
        arr[x] = y

N = int(sys.stdin.readline())  # number of nodes
M = int(sys.stdin.readline())  # number of edges
graph, parent = [], [0]*(N+1)

# 0-0) ๊ฐ„์„  ์—ฐ๊ฒฐ ์ •๋ณด ์ดˆ๊ธฐํ™”, ์ •๋ ฌ
for _ in range(M):
    src, end, cost = map(int, sys.stdin.readline().split())
    graph.append((cost, src, end))
graph.sort()

# 0-1) ์—ฐ๊ฒฐ ์ •๋ณด ์ดˆ๊ธฐํ™”
for i in range(1, N+1):
    parent[i] = i

# 1) Kruskal Algorithm
result = 0
for j in range(M):
    weight, start, final = graph[j]
    if find(parent, start) != find(parent, final):
        union(parent, start, final)
        result += weight

print(result)

find ๋ฉ”์„œ๋“œ๋Š” ์ž…๋ ฅํ•œ ๋…ธ๋“œ์˜ ๋ฃจํŠธ ๋…ธ๋“œ๋ฅผ ์ฐพ์•„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๊ฒƒ์„ ํ™œ์šฉํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ๋…ธ๋“œ๊ฐ€ ๊ฐ™์€ ์ง‘ํ•ฉ(ํŠธ๋ฆฌ)์— ์†ํ•˜๋Š”์ง€ ์†์‰ฝ๊ฒŒ ํŒ์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๊ฒƒ์€ ๋ฐ”๊ฟ” ์ƒ๊ฐํ•ด๋ณด๋ฉด ์„ ํƒ๋œ ๋‘ ๋…ธ๋“œ๊ฐ€ ์‚ฌ์ดํด์„ ๋ฐœ์ƒ์‹œํ‚ค๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์•Œ์•„ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋งŒ์•ฝ ๋‘ ๋…ธ๋“œ๊ฐ€ ๊ฐ™์€ ๋ฃจํŠธ ๋…ธ๋“œ๊ฐ’์„ ๊ฐ–๋Š”๋‹ค๋ฉด, ๊ฒฐ๊ตญ ๊ฐ™์€ ์ง‘ํ•ฉ(ํŠธ๋ฆฌ)์— ์†ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋ฉฐ, ์ด๊ฒƒ์€ ์‚ฌ์ดํด์„ ์œ ๋ฐœํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์‚ฌ์ดํด์„ ์œ ๋ฐœํ•˜๋Š” ์ •์ ์€ ์„ ํƒํ•˜์ง€ ์•Š์œผ๋ฉฐ, ํŠธ๋ฆฌ์˜ ์„ฑ์งˆ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ์„ ํƒํ•ด union ์—ฐ์‚ฐ์— ๋Œ€์ž…ํ•œ๋‹ค.

๐Ÿ”ดย Prim Algorithm (์ •์  ์„ ํƒ)

ํŠน์ • ์ •์ ์—์„œ ์‹œ์ž‘ํ•ด์„œ ๊ฐ€์ค‘์น˜๊ฐ€ ์ž‘์€ ๊ฐ„์„ ๋“ค ์ˆœ์„œ๋Œ€๋กœ ํŠธ๋ฆฌ๋ฅผ ํ™•์žฅํ•ด๋‚˜๊ฐ€๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์‹œ์ž‘์ ์„ ์ง€์ •ํ•œ๋‹ค๋Š” ์ ์—์„œ ๋‹ค์ต์ŠคํŠธ๋ผ์™€ ์œ ์‚ฌํ•˜๋ฉฐ, ๊ฐ„์„ ์˜ ์ˆซ์ž๊ฐ€ ๋งŽ์€ ๋ฐ€์ง‘ ๊ทธ๋ž˜ํ”„ ์ƒํ™ฉ์—์„œ Kruskal๋ณด๋‹ค ๋น ๋ฅด๋‹ค. ๊ตฌ์ฒด์ ์ธ ๋™์ž‘ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • 1) ์„ ํƒ ๋…ธ๋“œ๋ฅผ MST ์ง‘ํ•ฉ์— ์ถ”๊ฐ€
  • 2) MST ์ง‘ํ•ฉ์— ํฌํ•จ๋œ ๋…ธ๋“œ๋“ค์— ์ธ์ ‘ํ•œ ์ •์ ๋“ค ํƒ์ƒ‰
    • ์‚ฌ์ดํด ๋ฐœ์ƒ ์—ฌ๋ถ€ ํ™•์ธ
      • ์‚ฌ์ดํด ๋ฐœ์ƒ X: ์ตœ์†Œ ๊ฐ€์ค‘์น˜์˜ ๊ฐ„์„ ์„ ์„ ํƒ
  • 3) ์ „์ฒด ๊ฐ„์„ ์˜ ๊ฐœ์ˆ˜๊ฐ€ N-1๊ฐœ๊ฐ€ ๋  ๋•Œ๊นŒ์ง€, 1 & 2 ๊ณผ์ • Iteration

๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” O(N^2)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ธฐ๋กํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ž๋ฃŒ๊ตฌ์กฐ ์ตœ์ ํ™”์— ๋”ฐ๋ผ์„œ Kruskal๊ณผ ๋น„์Šทํ•œ ์‹œ๊ฐ„๋ณต์žก๋„์ธ O(ElogE)์ •๋„๋กœ๊นŒ์ง€ ๋งŒ๋“ค์–ด ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์ตœ์†Œ ํž™์ •๋ ฌ๊ณผ ์šฐ์„ ์ˆœ์œ„ ํ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค. ํž™์ •๋ ฌ์„ ์ด์šฉํ•ด ๊ทธ๋ž˜ํ”„ ์—ฐ๊ฒฐ ์ •๋ณด๋ฅผ ๊ฐ€์ค‘์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ์„ ํ•œ ๋’ค์—, ์‚ฌ์ดํด์„ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š๋Š” ์ธ์ ‘ ๋…ธ๋“œ๋ฅผ ์„ ํƒํ•˜๋„๋ก ๋งŒ๋“ ๋‹ค.

""" prim algorithm example: baekjoon 1197 """

import sys, heapq
from typing import List
"""
[ํ’€์ด]
1) Prim with ์šฐ์„ ์ˆœ์œ„ ํ (ํž™)
    - ์‹œ์ž‘์  ์„ ํƒ, MST ์ง‘ํ•ฉ์— ์ถ”๊ฐ€
    - MST ์ง‘ํ•ฉ์˜ ๋…ธ๋“œ๋“ค์— ์ธ์ ‘ํ•œ ๋ชจ๋“  ์ •์  ํƒ์ƒ‰
        - ์‚ฌ์ดํด ๋ฐœ์ƒ ์—ฌ๋ถ€ ํ™•์ธ: ๋ฐฉ๋ฌธ ์—ฌ๋ถ€๋กœ ํŒ์ •
        - ์‚ฌ์ดํด ๋ฐœ์ƒ X: ์ตœ์†Œ ๊ฐ€์ค‘์น˜ ๊ฐ„์„  ์„ ํƒ (heapify๋ฅผ ํ†ตํ•ด ๊ฐœ๋ณ„ ๋…ธ๋“œ๋งˆ๋‹ค ๊ฐ„์„ ๋“ค์„ ๊ฐ€์ค‘์น˜ ๊ธฐ์ค€ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ)
"""

def prim(grid: List[List], visit: List[bool], start: int) -> int:
    visit[start] = True
    tmp = grid[start]  # ์„ ํƒ๋œ ๋…ธ๋“œ์— ๋Œ€ํ•œ ๋ชจ๋“  ์ธ์ ‘ ๊ฐ„์„  ์ถ”์ถœ
    heapq.heapify(tmp)  # ์ด๋ฏธ ์ƒ์„ฑ๋˜์–ด ์žˆ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์— ๋Œ€ํ•ด์„œ๋Š” heapq.heapify๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํž™ ์„ฑ์งˆ์„ ๋งŒ์กฑํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค
    mst, total = [], 0
    while tmp:
        weight, u, v = heapq.heappop(tmp)
        if not visit[v]:  # ๋ฏธ๋ฐฉ๋ฌธ ๋…ธ๋“œ๋กœ์˜ ๊ฐ„์„ ๋งŒ ์„ ํƒํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ์‚ฌ์ดํด ๋ฐœ์ƒ ์—ฌ๋ถ€ ํŒ์ •ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„
            visit[v] = True
            mst.append((u, v))
            total += weight
            for edge in graph[v]:
                if not visit[edge[2]]:
                    heapq.heappush(tmp, edge)
    return total

def solution():
    result = prim(graph, visited, 1)  # ์‹œ์ž‘ ๋…ธ๋“œ๋ฅผ ์–ด๋–ค ๊ฒƒ์œผ๋กœ ์„ค์ •ํ•ด๋„ ์ƒ๊ด€ ์—†์Œ
    print(result)

if __name__ == "__main__":
    sys.setrecursionlimit(10**6)
    V, E = map(int, sys.stdin.readline().split())
    graph, visited = [[] for _ in range(V+1)], [False]*(V+1)
    for _ in range(E):
        src, end, cost = map(int, sys.stdin.readline().split())
        graph[src].append([cost, src, end])
        graph[end].append([cost, end, src])
    solution()

์‹œ์ž‘ ์ •์ ์€ ์•„๋ฌด๊ฑฐ๋‚˜ ์„ ํƒํ•ด๋„ ์ƒ๊ด€์—†๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ€์žฅ ์ฃผ๋ชฉํ•  ๋ถ€๋ถ„์€ ๋…ธ๋“œ ์„ ํƒ์‹œ ์‚ฌ์ดํด ์—ฌ๋ถ€๋ฅผ ํŒ์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ–ˆ๋Š”๊ฐ€์ด๋‹ค. ๊ฐœ๋ณ„ ๋…ธ๋“œ์— ๋Œ€ํ•œ ๋ฐฉ๋ฌธ์—ฌ๋ถ€๋ฅผ ๊ธฐ๋กํ•˜๋Š” ๋ฐฐ์—ด์„ ๋”ฐ๋กœ ์ƒ์„ฑํ•œ ๋’ค, ๋ฐฉ๋ฌธ(ํ•ด๋‹น ๋…ธ๋“œ์™€ ์—ฐ๊ฒฐ๋˜๋Š” ๊ฐ„์„  ์„ ํƒ)ํ•  ๋•Œ ๋งˆ๋‹ค ๋ฐฉ๋ฌธ ๊ธฐ๋ก์„ ์ €์žฅํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋งŒ์•ฝ ์–ด๋–ค ๋…ธ๋“œ๋ฅผ ์„ ํƒํ–ˆ์„ ๋•Œ, ์ด๋ฏธ ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ๋ผ๋ฉด ํ•ด๋‹น ๋…ธ๋“œ์™€ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฐ„์„ ์˜ ๊ฐ€์ค‘์น˜๊ฐ€ ํ˜„์žฌ ๊ฐ€์žฅ ์ตœ์†Œ์— ํ•ด๋‹นํ•˜๋”๋ผ๋„ ์‚ฌ์ดํด์„ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— ์„ ํƒํ•˜์ง€ ์•Š๋„๋ก ์‚ฌ์ดํด ์—ฌ๋ถ€๋ฅผ ํŒ์ •ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๋‹ค.
Kruskal์ฒ˜๋Ÿผ ์ „์ฒด ๋ชจ๋“  ๊ฐ„์„ ์„ ์•Œ๊ณ  ์žˆ๋Š” ์ƒํƒœ๊ฐ€ ์•„๋‹˜์—๋„ ์ตœ์†Œ ์ŠคํŒจ๋‹ ํŠธ๋ฆฌ์˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด ๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š” ๋ฏธ๋ฆฌ ๊ฐœ๋ณ„ ๋…ธ๋“œ๋ณ„ ๊ฐ„์„ ๋“ค์„ ๊ฐ€์ค‘์น˜ ๊ธฐ์ค€์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ ํ•ด๋’€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๊ฒƒ ๋•Œ๋ฌธ์— ์ง€์—ญ ์ตœ์ ๋“ค์˜ ํ•ฉ์ด ์ „์—ญ ์ตœ์ ์ด ๋˜์–ด์•ผ ํ•˜๋Š” ๊ทธ๋ฆฌ๋””์˜ ์ œ์•ฝ ์กฐ๊ฑด์„ ๋งŒ์กฑ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

Leave a comment