스패닝 트리
: 그래프에서 일부 간선을 선택해서 만든 트리
: 스패닝 트리는 트리의 특수한 형태이므로 모든 정점들이 연결되어 있어야 하고 사이클을 포함해서는 안됨 ( 트리의 정의가 사이클 없이 모든 정점이 연결되어 있는 그래프)
: 스패닝 트리는 그래프에 있는 n개의 정점을 n-1개의 간선으로 연결
최소 스패닝 트리
: 그래프에서 tree를 만들 때, 스패닝 트리 중에 선택한 간선의 가중치의 합이 최소인 트리
: n개의 정점을 가지는 그래프에 대해 반드시 n-1개의 간선만을 사용해야 함
: 사이클이 포함되어서는 안됨
: Prim 알고리즘과 Kruskal 알고리즘이 대표적임 (가장 중요한 것은 사이클을 만들지 않는다는 것)
Prim, Kruskal 알고리즘 비교
: Prim 알고리즘 -> 시작점에서 끝점까지 단계적으로 확장, 정점 선택을 기준으로 최적해 찾기
: Kruskal 알고리즘 -> 가중치를 간선에 할당, 간선 선택을 기준으로 최적해 찾기
(예시) 백준 1922 네트워크 연결 문제
import sys
import heapq
rdln = sys.stdin.readline
def prim(v):
q = []
mst[v] = 1 # 방문했음을 표시하기 위한 배열, 1은 방문을 의미
result = 0
for i in adj[v]:
heapq.heappush(q, i)
while q:
c, v = heapq.heappop(q)
if not mst[v]:
mst[v] = 1
result += c
for j in adj[v]:
heapq.heappush(q, j)
if sum(mst) == n:
return result
n = int(rdln())
m = int(rdln())
adj = [[] for _ in range(n+1)]
mst = [0] * (n+1)
for _ in range(m):
a, b, c = map(int, rdln().split())
adj[a].append([c, b])
adj[b].append([c, a])
print(prim(1))
(예시) 백준 1197 최소 스패닝 트리 문제
def find(i):
if parent[i] != i:
parent[i] = find(parent[i])
return parent[i]
def union(irep, jrep):
if rank[irep] <= rank[jrep]:
parent[irep] = jrep
if rank[irep] == rank[jrep]:
rank[jrep] += 1
else:
parent[jrep] = irep
def Kruskal(graph):
mst_cost = 0
for i, j, wt in graph:
irep, jrep = find(i), find(j)
if irep != jrep:
union(irep, jrep)
mst_cost += wt
return mst_cost
v, e = map(int, rdln().split())
graph = []
parent = [i for i in range(v+1)]
rank = [0] * (v+1)
for _ in range(e):
a, b, c = map(int, rdln().split())
graph.append((a, b, c))
graph.sort(key = lambda x:x[2])
sys.stdout.write(f"{Kruskal(graph)}")