Prim演算法求圖的最小生成樹
阿新 • • 發佈:2018-12-01
演算法之-----使用prim演算法求得最小生成樹的權值
程式碼實現:
1.輸入:n,m(n代表無向圖頂點數,m代表邊數)
輸入:m行(每行輸入內容為(i,j,c)分別代表每條邊的起點、終點和權值)
2. 輸出:最小生成樹的權值
/*---prim演算法時間複雜度O(n^2),n為頂點數, 時間複雜度與邊的數目無關,因此適用於求邊稠密的圖的最小生成樹---*/ #include<stdio.h> #include<stdlib.h> #include<limits.h> #include<stdbool.h> #define MAX_VERTEX_NUM 20 //圖中頂點最大個數 #define INFINITY INT_MAX //無窮大∞ typedef char VertexType; //頂點名稱型別 typedef int VRType; //邊的權值型別 //使用鄰接矩陣作為圖的儲存結構 typedef struct { VertexType vexs[MAX_VERTEX_NUM]; //頂點向量 VRType arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //鄰接矩陣,其值為相鄰頂點的邊的權值 int vexnum,arcnum; //圖的頂點數和邊數 }MGraph; //建立圖 //獲取頂點在頂點向量中的下標,不存在返回-1 int locateVertex(MGraph G, VertexType v) { int i; for(i=0;i<G.vexnum;i++) if(G.vexs[i]==v) return i; return -1; } void createMGraph(MGraph *mg) { int i,j; int M[20]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t'}; //輸入圖的頂點數和邊數 scanf("%d %d",&(mg->vexnum),&(mg->arcnum)); getchar(); //輸入圖的頂點名稱 for(i=0;i<mg->vexnum;i++) { mg->vexs[i]=M[i]; } //初始化鄰接矩陣 for(i=0;i<mg->vexnum;i++) for(j=0;j<mg->vexnum;j++) mg->arcs[i][j] = INFINITY; //輸入邊的兩個頂點個權值v1 v2 w char v1,v2; int w,k,m; for(k=0;k<mg->arcnum;k++) { //輸入第%d條邊兩個頂點和權值 scanf("%c %c %d",&v1,&v2,&w); getchar(); i = locateVertex(*mg,v1); j = locateVertex(*mg,v2); mg->arcs[i][j] = mg->arcs[j][i] = w; //無向圖 // mg->arcs[i][j] = w; //有向圖 } } //prim演算法構造圖的最小生成樹 //記錄從頂點集U到V-U的代價最小的邊的輔助陣列定義 typedef struct { VertexType adjvex; //頂點名稱 VRType lowcost; //對應邊的權值 }closedge[MAX_VERTEX_NUM]; void PRIM(MGraph G, VertexType u) { int k,i,j,sumw=0; closedge closedge; k = locateVertex(G,u); //獲取起始頂點的下標 //初始化輔助陣列 for(i=0;i<G.vexnum;i++) { if(i!=k) { closedge[i].lowcost = G.arcs[k][i]; closedge[i].adjvex = u; } } closedge[k].lowcost = 0; //初始,U={u} //最小生成樹邊及權值 for(i=1;i<G.vexnum;i++) //選擇其餘G.vexnum-1個頂點 { int min = INFINITY,v,index = k; for(v=0;v<G.vexnum;v++) //求出最小生成樹下一個結點:第index頂點 { if(closedge[v].lowcost<min && closedge[v].lowcost!=0 && closedge[v].lowcost!=INFINITY) { min = closedge[v].lowcost; index = v; } } sumw = sumw+closedge[index].lowcost; closedge[index].lowcost = 0; //將第index個頂點併入U for(j=0;j<G.vexnum;j++) { if(G.arcs[index][j]<closedge[j].lowcost) //新頂點併入後重新選擇最小邊 { closedge[j].adjvex = G.vexs[index]; closedge[j].lowcost = G.arcs[index][j]; } } } //最小生成樹權值 printf("%d\n",sumw); } int main() { MGraph mg; createMGraph(&mg); PRIM(mg,mg.vexs[0]); }
最小生成樹的性質:
MST性質:假設G=(V,E)是一個連通網,U是頂點V的一個非空子集。若(u,v)是一條具有最小權值的邊,其中u∈U,v∈V-U,則必存在一棵包含邊(u,v)的最小生成樹。
構造網的最小生成樹必須解決下面兩個問題:
(1)儘可能選取權值小的邊,但不能構成迴路;
(2)選取n-1條恰當的邊以連通n個頂點;
prim演算法基本方法:
從連通網路N = { V, E }中的某一頂點u0出發,選擇與它關聯的具有最小權值的邊(u0, v),將其頂點加入到生成樹的頂點集合U中。以後每一步從一個頂點在U中,而另一個頂點不在U中的各條邊中選擇權值最小的邊(u, v),把該邊加入到生成樹的邊集TE中,把它的頂點加入到集合U中。如此重複執行,直到網路中的所有頂點都加入到生成樹頂點集合U中為止。
假設G=(V,E)是一個具有n個頂點的帶權無向連通圖,T(U,TE)是G的最小生成樹,其中U是T的頂點集,TE是T的邊集,則構造G的最小生成樹T的步驟如下:
(1)初始狀態,TE為空,U={v0},v0∈V;
(2)在所有u∈U,v∈V-U的邊(u,v)∈E中找一條代價最小的邊(u′,v′)併入TE,同時將v′併入U;
重複執行步驟(2)n-1次,直到U=V為止。