與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 }
這個代碼沒有寫全,由於這樣用的次數少的可憐了。都用它的升級版了
首先,針對排序的問題,排序隨你選,接下來就是判斷是否構成環的問題了。這裏用並查集輕易的實現
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 }