最小生成樹(prim算法,Kruskal算法)c++實現


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 }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM