最小生成樹是指帶權無向圖中,其各邊權值和最小的生成樹。這個問題在日常生活中會廣泛遇到,如何用最小的代價把網絡中各點連接起來。
常用的算法有Kruskal,Prim,我們對這兩個典型算法進行Python實現。
Kruskal
Kruskal算法基於簡單連通分量的最小代價互聯。將初始圖G中各邊按權值從小到大排列成列表edges,存儲方式為 (weight, vi, vj),每次取出一條邊,檢查其連接的兩端是否已連通,若尚未連通則將該邊加入生成樹,並修改該邊所連接的兩個連通分量的狀態,否則刪除該邊。相應的Python代碼實現如下:
1 def Kruskal(graph): 2 vnum = graph.vertex_num() #得到圖中點的個數 3 mst, edges = [], [] 4 reps = [i for i in range(vnum)] #初始化代表元 5 for vi in range(vnum): #收集各邊 6 for vj,weight in graph.out_edges(vi): 7 edges.append((weight,vi,vj)) 8 edges.sort() #將邊按權值weight從小到大排序 9 for weight, vi, vj in edges: #逐個遍歷邊,將其加入到mst中 10 if reps[vi] != reps[vj]: 11 mst.append((vi, vj, weight)) 12 repi, repj = reps[i], reps[j] 13 for v in range(vnum): #更新代表元 14 if reps[v] == repj: 15 reps[v] = repi 16 return mst
Prim
Prim算法是基於所謂的MST准則,將圖的點集分為兩部分,mst和V,依次將邊頂點分屬於兩個點集的最小權值邊加入到生成樹中,同時將V中連接的點加入到mst中,相比於Kruskal不斷將最小權值邊加入生成樹,Prim則是連續擴大最小生成樹中的點集。
相應的Python代碼實現如下:
1 def Prim(graph): 2 vnum = graph.vertex_num() 3 edges = PrioQueue((0,0,0)) #每次將新邊加入到一個優先隊列中 4 mst = [None] * vnum #用於判斷邊所連接的點是否已經遍歷過 5 edge_count = 0 6 while edge_count < vnum and not edges.is_empty(): 7 weight, vi, vj = edges.dequeue() 8 if mst[vj] == None: 9 edge_count += 1 10 mst[vj] = (vi, weight) 11 for i,w in graph.out_edges(vj): #將新點的出邊加入優先隊列 12 if not mst[i]: 13 edges.enqueue((w, vj, i)) 14 return mst