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;
}
原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/275193.html