求最小生成树的算法——Kruskal
- 思路 :先把所有的边排个序,然后枚举所有的边(从小到大),如果当前边所连的两个点并没有在同一个集合里(这一可以用并查集来实现)(需要判断两个点是否已经连通,如果已经连通了,那么再用这条边连一遍就没有什么意义了),就连上这条边了。如果已经连了n - 1条边(n - 1条边就可以将一个图变为一个连通图),就直接退出,如果到最后都没有连上n - 1条边,当前图则不连通。
- 算法流程:
- 输入所有的边,并将他们存在一个结构体中
- 以边权大小值进行从小到大的排序
- 设定一个记录一共连了多少条边的k和一个存最小生成树边权总和的ans
- 枚举所有边,如果已经连了n - 1条边就退出
- 如果当前边的两个端点没有在同一个集合里,就把它们连起来并且ans的值加上此边的边权,k也加一
- 代码:
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 int n, m, v, k, ans, fa[1000001]; 5 struct node//定义结构体存图 6 { 7 int x, y, z;//z表示x连y的权值 8 }stu[1000001]; 9 inline int find(int x)//并查集 10 { 11 if(x != fa[x]) 12 { 13 fa[x] = find(fa[x]); 14 } 15 return fa[x]; 16 }//查找 17 inline void unity(int x, int y) 18 { 19 int r1 = find(x); 20 int r2 = find(y); 21 fa[r1] = r2; 22 return; 23 }//合并 24 inline int cmp(node a, node b)//从小到大结构体排序 25 { 26 return a.z < b.z; 27 } 28 signed main() 29 { 30 scanf("%d %d", &n, &m); 31 for(register int i = 1; i <= n; ++i) 32 { 33 fa[i] = i;//并查集初始化 34 } 35 for(register int i = 1; i <= m; ++i) 36 { 37 scanf("%d %d %d", &stu[i].x, &stu[i].y, &stu[i].z); 38 } 39 sort(stu + 1, stu + m + 1, cmp);//排序 40 for(register int i = 1; i <= m; ++i) 41 { 42 if(find(stu[i].x) != find(stu[i].y)) 43 { 44 ans += stu[i].z;//加上最小生成树中边的权值 45 unity(stu[i].x, stu[i].y);//连接起来 46 ++k;//记录边数 47 if(k == n - 1)//n - 1条边就行了 48 { 49 printf("%d", ans); 50 return 0; 51 } 52 } 53 } 54 return 0; 55 }