1、生成樹的概念
連通圖G的一個子圖如果是一棵包含G的所有頂點的樹,則該子圖稱為G的生成樹。
生成樹是連通圖的極小連通子圖。所謂極小是指:若在樹中任意增加一條邊,則將出現一個回路;若去掉一條邊,將會使之變成非連通圖。 生成樹各邊的權值總和稱為生成樹的權。權最小的生成樹稱為最小生成樹。
2、最小生成樹的性質
用哲學的觀點來說,每個事物都有自己特有的性質,那么圖的最小生成樹也是不例外的。按照生成樹的定義,n 個頂點的連通網絡的生成樹有 n 個頂點、n-1 條邊。
3、構造最小生成樹,要解決以下兩個問題:
(1).盡可能選取權值小的邊,但不能構成回路(也就是環)。
(2).選取n-1條恰當的邊以連接網的 n個頂點。
求最小生成樹的算法一般都使用貪心策略,有Prim算法和Krusal算法等。
普里姆算法的基本思想:
1)清空生成樹,任取一個頂點加入生成樹;
2)在那些一個端點在生成樹里,另一個端點不在生成樹里的邊中,選取一條權最小的邊,將它和另一個端點加進生成樹;
3)重復步驟2,直到所有的頂點都進入了生成樹為止,此時的生成樹就是最小生成樹。
即:從連通網絡 N = { V, E }中的某一頂點 u0 出發,選擇與它關聯的具有最小權值的邊(u0, v),將其頂點v加入到生成樹的頂點集合U中。以后每一步從一個頂點在U中,而另一個頂點不在U中的各條邊中選擇權值最小的邊(u, v),把它的頂點 v加入到集合U中。如此繼續下去,直到網絡中的所有頂點都加入到生成樹頂點集合U中為止。
1 #include<iostream> 2 using namespace std; 3 4 #define MAX 100 5 #define MAXCOST 0x7fffffff 6 7 int graph[MAX][MAX]; 8 9 int Prim(int graph[][MAX], int n)//二維數組作為參數如何使用? 10 { 11 int sta[MAX];//存放某一條邊的起點值 12 int lowcost[MAX];//存放以i為終點的的邊的最小的權值 13 int min,minid,sum=0;//min用來存放最小權值,minid用來存放權值最小的邊所對應的終點 14 for(int i=2;i<=n;i++) 15 { 16 lowcost[i]=graph[1][i];//初始化lowcost[i],並把他們的初始值都看作是從節點1出發到i的權值 17 sta[i]=1;//起點賦值為1 18 } 19 sta[1]=0;//節點1進入最小生成樹 20 for(int h=2;h<=n;h++) 21 { 22 min=MAXCOST;//找到最小的,先來個較大值 23 for(int j=2;j<=n;j++) 24 { 25 if(lowcost[j]<min&&lowcost[j]!=0)//如果找到權值較小的就賦值給min,並把終點j賦值給minid。 26 { min=lowcost[j]; minid=j;} 27 } 28 lowcost[minid]=0;//這條邊已經進入最小生成樹,所以把值置為0 29 sum+=min; 30 for(int s=2;s<=n;s++) 31 { 32 if(lowcost[s]<graph[minid][s])//如果原先的lowcost[j]的值大於以minid為起點到終點j的權值,則更新它,並把起點更新為minid 33 { 34 lowcost[s]=graph[minid][s]; 35 sta[s]=minid; 36 } 37 } 38 } 39 return sum; 40 41 } 42 int main() 43 { 44 int m,n,x,y,cost; 45 cout<<"請輸入節點數目和邊的數目:"<<endl; 46 cin>>m>>n; 47 for(int i=1;i<=m;i++) 48 for(int j=1;j<=m;j++) 49 graph[i][j]=MAXCOST; 50 51 for(int k=1;k<=n;k++) 52 { 53 cin>>x>>y>>cost; 54 graph[x][y]=graph[y][x]=cost; 55 } 56 cost= Prim(graph,n); 57 cout<<cost<<endl; 58 return 0; 59 }
prim函數應當好好理解,並且要多些幾遍才能熟練掌握。
Kruskal算法的步驟:
1.對所有邊進行從小到大的排序。
2.每次選一條邊(最小的邊),如果如果形成環,就不加入(u,v)中,否則加入。那么加入的(u,v)一定是最佳的。
1 #include <iostream> 2 #include<algorithm> 3 using namespace std; 4 5 #define MAX 100 6 struct edge 7 { 8 int x,y; 9 int w; 10 }e[MAX]; 11 int fa[MAX]; 12 int rank[MAX]; 13 int sum; 14 int cmp(edge a,edge b)//排序函數 15 { 16 if(a.w!=b.w) 17 return a.w<b.w; 18 else 19 { 20 return a.x<b.x; 21 } 22 } 23 void make_set(int x)//初始化節點 24 { 25 fa[x]=x; 26 rank[x]=0; 27 } 28 int find(int x)//查找父節點 29 { 30 return fa[x]==x?x:fa[x]=find(fa[x]); 31 } 32 33 34 void union_set(int x,int y,int w)//合並節點 35 { 36 if(rank[x]>rank[y]) 37 { 38 rank[y]=x; 39 } 40 else if(rank[x]<rank[y]) 41 { 42 rank[x]=y; 43 } 44 else 45 { 46 rank[x]++; 47 rank[y]=x; 48 } 49 sum+=w;//總權值加上w 50 } 51 int main() 52 { 53 int x,y,w; 54 int m,n;//n是點,m是邊 55 cin>>n>>m; 56 for(int i=0;i<m;i++) 57 { 58 cin>>x>>y>>w; 59 e[i].x=x; 60 e[i].y=y; 61 e[i].w=w; 62 make_set(x); 63 make_set(y); 64 } 65 sort(e,e+m,cmp); 66 sum=0; 67 for(int i=0;i<n;i++) 68 { 69 x=find(e[i].x); 70 y=find(e[i].y); 71 w=e[i].w; 72 if(x!=y) 73 { 74 union_set(x,y,w); 75 } 76 } 77 cout<<sum<<endl; 78 return 0; 79 }