蒟蒻飘过...很基础的一个算法,主要为了加深理解,而且蒟蒻的代码画风很清真
从这篇博客学习了不少,而且配了很详细的图解 点击打开链接
Kruskal是寻找最小生成树的算法之一,按边权贪心
大致算法如下:
1)原图有n个顶点,m条边。将m条边从小到大排序
2)新建一个与原图有相同节点而没有边的图(不用建),从最小的边开始遍历,将新图中已经连上的节点打上标记
3)对于每条边,检查连接后是否会成环(用并查集,如果连接之前两端的标记就是一样的,则不可连)
4)记录已连接的边的条数,当连上n-1条边时,n个点都在树上了,最小生成树建成
附代码(只有并查集用了路径压缩画风不清真...第一次听学长讲的就长这样...点击打开链接上的并查集很清真)
洛谷 3366
#include <cstdio>
#include <algorithm>
using namespace std;
int f[5005]; //并查集标记记录
struct edge{
int u,v,w; //储存边的信息,u,v为始、终点,w为权值
}e[200010];
int ff(int x){
return f[x]==x?x:f[x]=ff(f[x]); //并查集,找到最初始的标记值
}
void merge(int x,int y){
if(ff(x)!=ff(y))f[ff(x)]=ff(y); //如果不在同一个联通块,就合并
}
bool cmp(edge x,edge y){
return x.w<y.w; //返回权值较小的边,使排序从小到大
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
} //输入
sort(e+1,e+m+1,cmp); //排序
int num=0,ans=0;
for(int i=1;;i++){
if(ff(e[i].u)!=ff(e[i].v)){ //如果不成环,即未联通
merge(e[i].u,e[i].v); //合并(联通)
ans+=e[i].w; //总权值加上新边权值
num++;
if(num==n-1)break; //已连上n-1条边时,跳出循环
}
}
printf("%d",ans);
}