prim演算法模板—最小生成樹
設G = (V,E)是無向連通帶權圖,即一個網路。E中的每一條邊(v,w)的權為c[v][w]。如果G的子圖G’是一棵包含G的所有頂點的樹,則稱G’為G的生成樹。生成樹上各邊權的總和稱為生成樹的耗費。在G的所有生成樹中,耗費最小的生成樹稱為G的最小生成樹。構造最小生成樹的兩種方法:Prim演算法和Kruskal演算法。
一、最小生成樹的性質
設G = (V,E)是連通帶權圖,U是V的真子集。如果(u,v)∈E,且u∈U,v∈V-U,且在所有這樣的邊中,(u,v)的權c[u][v]最小,那麼一定存在G的一棵最小生成樹,它意(u,v)為其中一條邊。這個性質有時也稱為MST性質。
二、Prim演算法(與dijkstra演算法很相似)
設G = (V,E)是連通帶權圖,V = {1,2,…,n}。構造G的最小生成樹Prim演算法的基本思想是:首先置S = {1},然後,只要S是V的真子集,就進行如下的貪心選擇:選取滿足條件i ∈S,j ∈V – S,且c[i][j]最小的邊,將頂點j新增到S中。這個過程一直進行到S = V時為止。在這個過程中選取到的所有邊恰好構成G的一棵最小生成樹。
如下帶權圖:
生成過程:
1 -> 3 : 1
3 -> 6 : 4
6 -> 4: 2
3 -> 2 : 5
2 -> 5 : 3
C語言程式碼:
void Prim(){ int i,j,k,tmp,ans; for(i=1;i<=n;i++) dis[i]=inf;//初始化 dis[1]=0; for(i=1;i<=n;i++){ tmp=inf; for(j=1;j<=n;j++){ if(!vis[j]&&tmp>dis[j]){ tmp=dis[j]; k=j; }//找出最小距離的節點 } vis[k]=1;//把訪問的節點做標記 for(j=1;j<=n;j++){ if(!vis[j]&&dis[j]>map[k][j]) dis[j]=map[k][j];//更新最短距離 } } }
三、Kruskal演算法
當圖的邊數為e時,Kruskal演算法所需的時間是O(eloge)。當e = Ω(n^2)時,Kruskal演算法比Prim演算法差;但當e = o(n^2)時,Kruskal演算法比Prim演算法好得多。
給定無向連同帶權圖G = (V,E),V = {1,2,...,n}。Kruskal演算法構造G的最小生成樹的基本思想是:
(1)首先將G的n個頂點看成n個孤立的連通分支。將所有的邊按權從小大排序。
(2)從第一條邊開始,依邊權遞增的順序檢查每一條邊。並按照下述方法連線兩個不同的連通分支:當檢視到第k條邊(v,w)時,如果端點v和w分別是當前兩個不同的連通分支T1和T2的端點是,就用邊(v,w)將T1和T2連線成一個連通分支,然後繼續檢視第k+1條邊;如果端點v和w在當前的同一個連通分支中,就直接再檢視k+1條邊。這個過程一個進行到只剩下一個連通分支時為止。
此時,已構成G的一棵最小生成樹。
Kruskal演算法的選邊過程:
1 -> 3 : 1
4 -> 6 : 2
2 -> 5 : 3
3 -> 4 : 4
2 -> 3 : 5