最小生成樹-Kruskal算法

Prim算法貪心選擇不一樣,Kruskal算法採起每次選擇權值最小的邊的方法,這樣,在不構成環且最後可以鏈接完全部邊它們的權重和必定是最小的。html

和以前Prim算法的圖同樣,便於區別兩者。node

Kruskal既然是選擇最小的邊,那麼就先找一個最小的出來,是1-6(10)ios

而後繼續找出剩下的邊中最小一條邊,是3-4(12)算法

繼續找一條最小的出來,2-7(14)數組

在來,爲了區別已經選擇的點,我把點的顏色也作個標記,有顏色的表示爲已經加入生成樹的點ide

喔,忘了把最小的邊2-3(16)選了spa

如今圖變成了這樣,(依舊難看).......3d

還沒找完,繼續找最小的邊..是7-4(18)code

你會發現我把這條邊用藍色標記了,是否是我爲了好玩??固然不是了,這條邊是有問題的。htm

這條邊雖然是上一次選擇完後剩下的邊中最短的,可是,它的左右兩個點已是最小生成樹的結點了,而把這條邊加入後,構成了右邊的一個大大的環。這樣顯然不是最小生成樹了.

再複習下,生成樹:一個連通圖的生成樹,是一個極小連通子圖,其中包含圖的全部結點,和構成一棵數的(n-1)條邊。若是在一棵生成樹的兩個結點上添加任意一邊,一定構成一個環。

最小生成樹:圖的全部生成樹中全部邊的權值和最小的那個生成樹

因此,有環的連生成樹都不是了,怎麼會是最小生成樹。。

因此,這條邊7-4(18)丟掉丟掉,從新選擇。選擇5-4(22)

好像圖中全部的點都有顏色了,可是還沒徹底好,由於它們還不是一條繩上的螞蚱,

繼續選,最短的是6-5(25)

繼續選 ,唉,不對,選了24發現又有環了,選28也構成環了。。。。在仔細一看,最小生成樹已經生成了

這個就是Kruskal算法的流程。那麼接下來講說代碼。

 1 struct node  2 {  3     int u;  4     int v;  5     int w;//邊的權重
 6 }Edge;  7 void Kruskal(Graph g)//無向圖g採用鄰接矩陣
 8 {  9     Edge E[MAXN];//存放圖中全部的邊
10     int vest[MAXN];//輔助數組,存放連通的點的編號
11     k = 0; 12     for(int i = 0;i < g.n;i++) 13  { 14         for(int j = 0; j <= i ;j++) 15  { 16             if(g.egdes[i][j] != 0 &&g.egdes[i][j]!= INF) 17             {//說明i到j邊
18                 E.[k].u = i; 19                 E.[k].v = j; 20                 E.[k].w = g.edges[i][j]; 21                 k++; 22  } 23  } 24     }//以上將全部的邊都加入到E數組中,確定是不重複的
25     Sort(E);//對邊集數組進行排序。
26     Init(vest);//將輔助數組初始化,即每一個結點一開始都沒有加入到最小生成樹中,因此它們各自爲一個陣營
27     j = 0; 28     Count = 0 ; 29     while(Count < g.n)//已經加入生成樹的結點數小於圖的結點數,代表生成樹沒生成完,
30  { 31         u1 = E[j].u; 32         v1 = E[j].v;//選出最短的邊
33         s1 = vest[u1]; 34         s2 = vest[v1];//獲得兩個所在集合的編號,
35         if(s1 != s2)//若是它們編號不等,,說明它們還每加入到同一個生成樹中,
36  { 37             //這裏能夠打印它們的編號 。。。
38             k++; 39             for(int i = 0; i< g.n;i++) 40  { 41                 if(vest[i]==s2) 42  { 43                     vest[i] = s1;//把屬於s2的那個點加入到s1所在點集合中
44                 }//即合併到一塊兒去,代表它們在一個生成樹中了,這樣就和 45                 //其餘沒有加入到的點區分開了
46  } 47  } 48         j++;//繼續找下一條邊
49  } 50 }
View Code

這個代碼沒有寫全,由於這樣用的次數少的可憐了。都用它的升級版了

首先,針對排序的問題,排序隨你選,接下來就是判斷是否構成環的問題了。這裏用並查集輕易的實現

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<vector>
 6 #include<stack>
 7 #include<map>
 8 #include<set>
 9 #include<list>
10 #include<queue>
11 #include<string>
12 #include<algorithm>
13 #include<iomanip>
14 using namespace std; 15 const int maxn = 100; 16 int par[maxn]; 17 int rank[maxn]; 18 int n; 19 int m; 20 
21 struct node 22 { 23     int Start; 24     int End; 25     int weight; 26 }edges[maxn]; 27 
28 int cmp(node a,node b)//按權值從小到大排序
29 { 30     return a.weight < b.weight; 31 } 32 
33 void Init(int n)//par初始化爲本身
34 { 35     for(int i = 1;i <= n;i++) 36  { 37         par[i] = i; 38  } 39 } 40 int  Find(int x)//找出父親結點
41 { 42     if(x != par[x])return x =Find(par[x]); 43     return x; 44 } 45 
46 int Kruskal() 47 { 48     int sum = 0; 49     for(int i = 1;i <= m ;i++) 50  { 51         int a = Find(edges[i].Start); 52         int b = Find(edges[i].End); 53         if(a != b)//父親結點不一樣
54  { 55             sum += edges[i].weight;//通常求最小生成樹的長度,這裏就沒去掉
56             par[a] = b;//合併集合
57  } 58  } 59     return sum; 60 } 61 
62 int main() 63 { 64     
65     cin>>n>>m; 66  Init(n); 67     for(int i = 1;i <= m;i++) 68  { 69         cin>>edges[i].Start>>edges[i].End>>edges[i].weight; 70  } 71     sort(edges+1,edges+1+n,cmp); 72     cout<<Kruskal(); 73     return 0; 74 }
View Code

傳送門:NetWork  不會的點這裏

相關文章
相關標籤/搜索