최소 신장 트리 (Mininum Spanning Tree)
"""
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
# 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
"""
예제
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]]