Kruskal算法求最小生成树
作者:互联网
AcWing 859
最小生成树的定义:
给定一张边带权的无向图 \(G=(V,E)\),其中 \(V\) 表示图中点的集合,\(E\)表示图中边的集合,\(n=|V|\),\(m=|E|\)
由$ V$ 中的全部 \(n\) 个顶点和 \(E\) 中 \(n−1\) 条边构成的无向连通子图被称为 \(G\) 的一棵生成树,其中边的权值之和最小的生成树被称为无向图 \(G\) 的最小生成树。
然后我们看Kruskal的算法思想
1.将所有边按照权重从小到大排序,时间复杂度为\(O(m\log m)\)
2.枚举每条边\(a,b\)的权重\(c\),如果\(a,b\)不连通的话,我们就把这一条边添加到集合当中。并查集实现合并、查询,时间复杂度\(O(m)\)
时间复杂度是很快的,所以在稀疏图当中,用\(Kruskal\)就可以了。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200010;
int n,m;
int p[N];//并查集的数组
struct Edge{
int a,b,w;
bool operator < (const Edge &W) const//重载运算符,用于后面排序
{
return w < W.w;
}
}edge[N];
int find(int x) // 并查集
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i ++ )
{
int a,b,w;
scanf("%d%d%d", &a, &b, &w);
edge[i] = {a,b,w};
}
sort(edge, edge + m);
for (int i = 1; i <= n; i ++ ) p[i] = i;
int res = 0;// 最小生成树里的所有权重之和
int cnt = 0;//当前加了多少条边
for (int i = 0; i < m; i ++ )
{
int a = edge[i].a, b = edge[i].b, w = edge[i].w;
a = find(a), b = find(b);//并查集查找根节点
if(a != b)
{
p[a] = b;//合并
res += w;
cnt ++ ;
}
}
if(cnt < n - 1) puts("impossible");
else printf("%d",res);
return 0;
}
标签:const,int,Kruskal,d%,最小,算法,edge,复杂度 来源: https://www.cnblogs.com/ljfyyds/p/16490086.html