在網絡搭建中,最小生成樹有其廣泛的應用.本文是作者學習了PRIM算法實現最小生成樹之后的筆記體會.歡迎指正批評.
1.概述
設G =(V,E)是無向連通帶權圖,即一個網絡。E中每條邊(v,w)的權為c[v][w]。如果G的子圖G’是一棵包含G的所有頂點的樹,則稱G’為G的生成樹。生成樹上各邊權的總和稱為該生成樹的耗費。在G的所有生成樹中,耗費最小的生成樹稱為G的最小生成樹。
網絡的最小生成樹在實際中有廣泛應用。例如,在設計通信網絡時,用圖的頂點表示城市,用邊(v,w)的權c[v][w]表示建立城市v和城市w之間的通信線路所需的費用,則最小生成樹就給出了建立通信網絡的最經濟的方案。
最小生成樹性質:
設G=(V,E)是連通帶權圖,U是V的真子集。如果(u,v)屬於E,且u屬於U,v屬於V-U,且在所有這樣的邊中,(u,v)的權c[u][v]最小,那么一定存在G的一棵最小生成樹,它以(u,v)為其中一條邊。這個性質有時也稱為MST性質。
2.PRIM算法
設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的一棵最小生成樹。
利用最小生成樹性質和數學歸納法容易證明,上述算法中的邊集合T始終包含G的某棵最小生成樹中的邊。因此,在算法結束時,T中的所有邊構成G的一棵最小生成樹。
例如,對於右圖中的帶權圖,按Prim算法選取邊的過程如下頁圖所示。
按Prim算法選取邊的過程如下頁圖所示。
在上述Prim算法中,還應當考慮如何有效地找出滿足條件i在S中,j也在V-S中,且權c[i][j]最小的邊(i,j)。實現這個目的的較簡單的辦法是設置2個數組closest和lowcost。
在Prim算法執行過程中,先找出V-S中使lowcost值最小的頂點j,然后根據數組closest選取邊(j,closest[j]),最后將j添加到S中,並對closest和lowcost作必要的修改。
用這個辦法實現的Prim算法所需的計算時間為O(n2).
以下是我參考<計算機算法分析與設計>王曉東第三版的代碼設計的程序.
#include <iostream> #define MAXINT 6 using namespace std; //聲明一個二維數組,C[i][j]存儲的是點i到點j的邊的權值,如果不可達,則用1000表示 //借此二維數組來表示一個連通帶權圖 int c[MAXINT][MAXINT]={{1000,6,1,5,1000,1000},{6,1000,5,1000,3,1000},{1,5,1000,5,6,4},{5,1000,5,1000,1000,2},{1000,3,6,1000,1000,6},{1000,1000,4,2,6,1000}}; void Prim(int n) { int lowcost[MAXINT];//存儲S中到達對應的其它各點的最小權值分別是多少 int closest[MAXINT];//closest[]數組保存的是未在S中的點所到達S中包含的最近的點是哪一個,如:closest[i]=1表示i最靠近的S中的點是1 bool s[MAXINT];//bool型變量的S數組表示i是否已經包括在S中 int i,k; s[0]=true;//從第一個結點開始尋找,擴展 for(i=1;i<=n;i++)//簡單初始化 { lowcost[i]=c[0][i]; closest[i]=0;//現在所有的點對應的已經在S中的最近的點是1 s[i]=false; } cout<<"0->"; for(i=0;i<n;i++) { int min=1000;//最小值,設大一點的值,后面用來記錄lowcost數組中的最小值 int j=1; for(k=1;k<=n;k++)//尋找lowcost中的最小值 { if((lowcost[k]<min)&&(!s[k])) { min=lowcost[k];j=k; } } cout<<j<<" "<<"->"; s[j]=true;//添加點j到集合S中 for(k=1;k<=n;k++)//因為新加入了j點,所以要查找新加入的j點到未在S中的點K中的權值是不是可以因此更小 { if((c[j][k]<lowcost[k])&&(!s[k])){lowcost[k]=c[j][k];closest[k]=j;} } } } int main() { //輸入初始化數組 cout<<"請輸入初始權值數組:"<<endl; for(int i=0;i<MAXINT;i++) { for(int j=0;j<MAXINT;j++) { // cout<<"please enter c["<<i<<"]["<<j<<"]:"; // cin>>c[i][j]; cout<<c[i][j]<<"\t"; // cout<<endl; } cout<<endl; } Prim(MAXINT-1); return 0; }