思路:图初始化完成后,将图内所有的边的权按照从小到大排,然后借用并查集的思想将所有点各自初始为一个集合,如果两个点存在某种方式连通,则将两个点的集合并起来,表示两点连通了,并将对应边的权累加上去,直到循环结束,如果结果发现集合内边不等于节点数-1,那么则说明不存在最小生成树。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int M = 1e5 + 10, N = M * 2;
int n,m,p[M];
struct edge
{
int a,b,w;
bool operator< (const edge &W)const
{
return w < W.w;
}
}edges[N];
int find(int x)//具体可看连通块那一节的笔记
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int kruskal()
{
int res=0,cnt=0;//res记录最小生成树所有边的权重和,cnt记录的是加入到最小树中边的数量
for(int i=0;i<m;i++)
{
int a=edges[i].a,b=edges[i].b,w=edges[i].w;
if(find(a)!=find(b))
//看a,b在不在同一个集合内,这里在不在一个集合可看作有没有连通起来
//如果两者已经在一个集合,再执行以下三行的话就会出现环,树是不允许出现环的
{
p[find(a)]=p[find(b)];//将a,b所在的两个集合合并起来
cnt++;//加入a<->b边
res+=w;//把a<->b边的权重加上去
}
}
if(cnt < n-1) return 0x3f3f3f3f;//因为树共有n个节点,如果全连通应该最后结果集合内会有n-1条边
else return res;
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++) p[i]=i;//初始化并查集
for(int i=0;i<m;i++)
{
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
edges[i]={a,b,w};
}
sort(edges,edges+m);//将边的权重按照从小到大排
int t = kruskal();
if(t==0x3f3f3f3f) printf("impossible\n");
else printf("%d\n",t);
return 0;
}
该程序使用Kruskal算法,通过并查集数据结构寻找图的最小生成树。首先对边按权重排序,然后遍历边,若两个顶点不在同一集合,则合并集合并将边权重累加,直至找到n-1条边。若最终边数少于n-1,表示无解。
973

被折叠的 条评论
为什么被折叠?



