演算法之最小生成樹
阿新 • • 發佈:2018-12-18
1. 問題描述:利用貪心演算法設計策略構造一個無向連通帶權圖的最小生成樹。
最小生成樹:設G=(V,E)是無向連通帶權圖,即一個網路。E中每條邊(v,w)的權為c[v][w]。包含G所有頂點的樹且該生成樹各邊權的總和最小(即耗費最小),則稱該生成樹為G的最小生成樹。
設G=(V,E)是無向連通帶權圖,頂點集V={1,2,…,n}。
1. Prim演算法基本思想:首先置頂點集S={1},然後只要S是V的真子集,就做如下貪心選擇:
選取滿足條件且c[i][j]最小的邊,並將頂點j新增到S中。直到S==V時為止。在這個過程中選擇的邊就構成G的一顆最小生成樹。
2. Kruskal
當處理到第k條邊(v,w)時,如果端點v和w分別是當前兩個不同連通分支T1、T2中的頂點時,就用邊(v,w)將T1、T2連線成一個連通分支,然後繼續處理下一條邊;如果v和w位於同一個連通分支中,就直接處理下一條邊;直到只剩下一個連通分支為止。
#include <iostream> using namespace std; #define N 6 #define MAX 10000 //頂點個數n,各邊權值c void Prim(int n,int c[N][N]) { int lowcost[n], //lowcost[i]=c[i][closest[i]]即i和鄰接頂點closest[i]邊的權值 closest[n]; //closest[i]表示頂點i的鄰接頂點(權值最小的鄰接頂點) bool s[n]; //頂點集s s[0]=true; //將第一個頂點新增進s中 for(int i=1;i<n;i++) //初始化各項 { lowcost[i]=c[0][i]; closest[i]=0; s[i]=false; } for(int i=1;i<n;i++) { int minc=MAX; int j=1; for(int k=1;k<n;k++) //找到lowcost陣列中最小的權值,記錄下標將該頂點新增進s中 { if(lowcost[k]<minc&&s[k]==false&&lowcost[k]>0) { minc=lowcost[k]; j=k; } } cout<<j+1<<" "<<closest[j]+1<<endl;//輸出選擇的邊 s[j]=true; for(int k=1;k<n;k++) //更新lowcost,看與當前j的值鄰接權值是否比與之前的j鄰接權值小,若小則更新鄰接頂點為當前的j { if(s[k]==false&&c[j][k]<lowcost[k]) { //cout<<j<<","<<k<<"--"<<c[j][k]<<"--"<<lowcost[k]<<endl; lowcost[k]=c[j][k]; closest[k]=j; } } } } int main() { int c[N][N]={ //0表示與自身的權值,MAX表示不可到達(非鄰接頂點) {0,6,1,5,MAX,MAX}, {6,0,5,MAX,3,MAX}, {1,5,0,5,6,4}, {5,MAX,5,0,MAX,2}, {MAX,3,6,MAX,0,6}, {MAX,MAX,4,2,6,0} }; Prim(N,c); }
複雜度分析:O(n^2)