/*
最小生成树:如果一个连通无向图不包含回路,那么就是一个树。最小生成树就是求权值最小的这棵树
思路:首先选择权值最小的边,然后选择次短的,直至选择了n-1条边为止。选边时,需要判断两个顶点是否已连通,已连通就不选。
比较难实现的是判断两个顶点是否连通,可以使用深搜或广搜,但是这样效率低。更好的选择是使用并查集:将所有顶点放入一个并查集,判断两个顶点是否在同一集合。
这种方法叫Kruskal算法。
测试示例:
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
*/
#include <stdio.h>
#include <algorithm>
#include <iostream>
typedef struct{
int u;
int v;
int w;
}Edge;//创建结构体用来存储边的关系
Edge e[1005];
int n,m;
int f[1005]={0},sum=0,count=0;//并查集用到的变量
bool cmp(Edge a,Edge b){
return a.w<b.w;
}
//并查集寻找祖先的函数
int getf(int u){
if(f[u]==u) return u;
//路径压缩
f[u]=getf(f[u]);
return f[u];
}
//并查集合并两子集合的函数
int merge(int u,int v){
int t1=getf(u);
int t2=getf(v);
if(t1!=t2){
f[t2]=t1;
return 1;
}
return 0;
}
int main()
{
int i;
//n表示顶点个数,m表示边的条数
scanf("%d%d",&n,&m);
//读入边
for(i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
//按照权值从小到大对边进行快速排序
//quicksort(1,m);
std::sort(e+1,e+m+1,cmp);
//并查集初始化
for(int i=1;i<=m;i++)
f[i]=i;
//Kruskal算法核心部分
for(i=1;i<=m;i++){//开始从小到大枚举每一条边
//判断一条边的两个定点是否已经连通,即判断是否已经在同一个集合中
if(merge(e[i].u,e[i].v)){
count++;
sum+=e[i].w;
}
if(count==n-1)//直到选到了n-1条边之后退出循环
break;
}
printf("%d\n",sum);
return 0;
}
最小生成树
最新推荐文章于 2024-07-05 14:38:31 发布