一、Prim演算法
概論
適合稠密圖,不進行堆最佳化的時間複雜度是\(O(n^2)\),進行堆最佳化則是\(O(mlogn)\)
每次將離連通部分的最近的點和點對應的邊加入的連通部分,連通部分逐漸擴大,最後將整個圖連通起來,並且邊長之和最小,基於一種貪心的策略。
證明的引理
對於任意切割 (S, V-S),其中 S 是生成樹 T 的節點集合,V-S 是未包含在 T 中的節點集合,存在一條橫切邊連線 S 和 V-S 中的頂點,並且該邊的權重是最小的。
禮貌拿圖:@Hasity【https://www.acwing.com/solution/content/38312/】
如果像記錄生成樹的邊的話,可以用一個pre陣列,在更新時記錄前驅節點!
程式碼
# prim演算法求最小生成樹
from math import inf
n,m = map(int,input().split())
g = [[inf] * (n + 1) for _ in range(n + 1)]
for _ in range(m):
u,v,w = map(int,input().split())
g[u][v] = g[v][u] = min(g[u][v],w)
vis = [False] * (n + 1)
dis = [inf] * (n + 1)
ans = 0
# dis[i]儲存的是節點i與已連通樹的最短距離
# 首先將1節點作為生成樹開始的起點
dis[1] = 0
for _ in range(n):
t = -1
# 尋找距離連通部分距離最短的節點將其納入生成樹的範圍
for i in range(1,n + 1):
if not vis[i] and (t == -1 or dis[t] > dis[i]):
t = i
vis[t] = True
# 如果一個點距離已結成的生成樹的距離為inf,那麼說明不存在一棵樹將所有點串起來
if dis[t] == inf:
print("impossible")
exit()
# 加 上 那 條 邊
ans += dis[t]
# 用新加入t點去更新剩餘的點到生成樹的最小距離!
for j in range(1,n + 1):
if dis[j] > g[t][j]:
dis[j] = g[t][j]
print(ans)