kruskal算法入门

【简介】克鲁斯卡尔算法是一种用来寻找最小生成树的算法。在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边。即给定一些线段的x,y和权值,当x,y不在一个集合的时候,选取权值最小的一个边,然后把x,y合并到一个集合中(并查集维护)

我们用现在来模拟一下Kruskal算法,下面给出一个无向图B,我们使用Kruskal来找无向图B的最小生成树。
这里写图片描述

首先,我们将所有的边都进行从小到大的排序。排序之后根据贪心准则,我们选取最小边(A,D)。我们发现顶点A,D不在一棵树上,所以合并顶点A,D所在的树,并将边(A,D)加入边集E。
这里写图片描述
我们接着在剩下的边中查找权值最小的边,于是我们找到的(C,E)。我们可以发现,顶点C,E仍然不在一棵树上,所以我们合并顶点C,E所在的树,并将边(C,E)加入边集E
这里写图片描述

不断重复上述的过程,于是我们就找到了无向图B的最小生成树,如下图所示!
这里写图片描述

核心代码:
初始化并查集

for (int i=1;i<=n;i++) fat[i]=i;//初始化并查集

并查集中的查询和合并操作

int ask(int x){//查找是否在同一集合
        if (fat[x]!=x) fat[x]=ask(fat[x]);
    return fat[x];
}
void unite (int x,int y){
    int x1=ask(x),x2=ask(y);
    if (x1==x2) return;
    else fat[x1]=x2;
}

另外,使用结构体存储边的x,y坐标和权值。

模板题:P3366 【模板】最小生成树
代码如下:

#include<cstdio>
#include<algorithm>
#define N (5010) 
#define M (200010)
using namespace std;
//定义结构体存边,x为起点,y为终点,z为值
struct edge{
    int x,y,z;
}a[M];
int fat[N],tot,ans;
bool cmp(edge x,edge y){//用于sort的排序,按值排
    return x.z<y.z;
} 
int ask(int x){//查找是否在同一集合
        if (fat[x]!=x) fat[x]=ask(fat[x]);
    return fat[x];
}
void unite (int x,int y){
    int x1=ask(x),x2=ask(y);
    if (x1==x2) return;
    else fat[x1]=x2;
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    sort(a+1,a+m+1,cmp);//把边按从大到小排
    for (int i=1;i<=n;i++) fat[i]=i;//初始化并查集
    for (int i=1;i<=m;i++){
        if (ask(a[i].x)!=ask(a[i].y)){//克鲁斯卡尔
            tot++;
            ans=ans+a[i].z;
            unite(a[i].x,a[i].y);
        }
    }
    if (tot<n-1) printf("orz");//判断若tot=k-1则生成了最小树
    else printf("%d",ans);
return 0;
}

注意,判断若tot=k-1则生成了最小树。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值