生成樹演算法

gebeng發表於2024-04-08

一、Prim演算法

概論

適合稠密圖,不進行堆最佳化的時間複雜度是\(O(n^2)\),進行堆最佳化則是\(O(mlogn)\)
每次將離連通部分最近的點點對應的邊加入的連通部分,連通部分逐漸擴大,最後將整個圖連通起來,並且邊長之和最小,基於一種貪心的策略。
證明的引理
對於任意切割 (S, V-S),其中 S 是生成樹 T 的節點集合,V-S 是未包含在 T 中的節點集合,存在一條橫切邊連線 S 和 V-S 中的頂點,並且該邊的權重是最小的。

image
禮貌拿圖:@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)

相關文章