Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪婪算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。
时间复杂度:elog2e e为图中的边数
原理可以参考这篇文章:
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html
实现如下:
1 #include <iostream> 2 #include <vector> 3 #include <queue> 4 #include <algorithm> 5 using namespace std; 6 7 vector<pair<int,int> > eg[100]; 8 9 typedef pair<int,int> pa; 10 11 struct node 12 { 13 int x,y,w; 14 15 node(int a,int b,int c) 16 { x=a;y=b;w=c;} 17 18 bool operator <(const node &a)const 19 { return w<a.w;} 20 //为了实现sort,<是升序(小的在前),>是降序 21 }; 22 23 void kruskal(int n,int d) 24 { 25 int vset[100]; 26 //辅助数组,判定两个顶点是否连通 27 28 vector<node> E; 29 //保存所有边 30 31 int k,j; 32 33 //init 34 for(int i = 0;i<n;i++) 35 { 36 vset[i] = i; 37 for(int j = 0;j<eg[i].size();j++) 38 { 39 pa x = eg[i][j]; 40 E.push_back(node(i,x.first,x.second)); 41 } 42 } 43 sort(E.begin(),E.end()); 44 45 k = 1; 46 //生成的边数,最后要刚好为总边数 47 int m = 0,sn1,sn2; 48 //E中的下标 49 50 while(k<n) 51 { 52 //sn1和sn2为两个集合 53 sn1 = vset[E[m].x]; 54 sn2 = vset[E[m].y]; 55 if(sn1!=sn2) 56 { 57 cout<<E[m].x<<"->"<<E[m].y<<" : "<<E[m].w<<endl; 58 //集合的表示 59 for(int i = 0;i<n;i++) 60 if(vset[i] == sn2) 61 vset[i] = sn1; 62 k++; 63 } 64 m++; 65 } 66 67 } 68 69 70 int main() 71 { 72 int n,d; 73 cin>>n>>d; 74 for(int i = 0;i<d;i++) 75 { 76 int t,s,w; 77 cin>>t>>s>>w; 78 eg[t].push_back(make_pair(s,w)); 79 eg[s].push_back(make_pair(t,w)); 80 } 81 kruskal(n,d); 82 83 84 85 } 86 /* 87 6 8 88 0 1 2 89 0 3 4 90 1 4 4 91 2 0 5 92 2 5 2 93 3 4 3 94 3 5 7 95 5 4 3 96 */
时间: 2024-10-18 15:51:59