【图论】最小生成树——kruskal算法

一、算法思想

 “边贪心”策略

边权递增对边排序,

两测试点是否在同一连通块中,

  • 不在则将当前边加入最小生成树
  • 在则舍弃

直到测试完所有边或者最小生成树生成完毕(边数=n-1)

伪代码: 

二、算法实现 

 由于需要对边权排序,使用邻接表每次都要遍历就不太好了,故直接定义

struct edge
{
    int u,v;//边的两端点
    int cost;//边权
}E[MAXN];

 

 将每个连通块当成一个集合

  • 判断两个端点是否在同一个集合中——查
  • 合并集合——并

使用“并查集”!

#include <iostream>
#include <algorithm>
#include <vector>
#define MAXN 510
#define MAXDATA 1000000000
using namespace std;

int nv,ne;

struct edge
{
    int u,v;//边的两端点
    int cost;//边权
}E[MAXN];

bool cmp(edge e1,edge e2){
    return e1.cost<e2.cost;
}

int father[MAXN];//并查集数组
int findFather(int x){
    //并查集查询函数,路径压缩
    if(father[x]<0) return x;
    else{
        return father[x]=findFather(father[x]);
    }
}
int UnionR(int root1,int root2){
    //按秩归并,也可以不按秩
    if(father[root1]<father[root2]){
        father[root1]+=father[root2];
        father[root2]=root1;
    }else{
        father[root2]+=father[root1];
        father[root1]=root2;
    }
}

int ans=0;
int cur_cnt=0;
int Kruskal(){
    //1:Initialize
    fill(father,father+nv,-1);
    sort(E,E+ne,cmp);
    for(int i=0;i<ne;i++){
        //检查每条边
        int faU=findFather(E[i].u);
        int faV=findFather(E[i].v);
        if(faU!=faV ||(faU==faV==-1)){//不在同一测试块中
            UnionR(faU,faV);//合并进同一测试块中
            ans+=E[i].cost;//权加入最小生成树中
            cur_cnt++;
            if(cur_cnt==(nv-1)) break;//生成完毕
        }
    }
    if(cur_cnt==(nv-1)) return ans;//存在且生成完毕
    else return -1;
}

int main(){
    scanf("%d %d",&nv,&ne);

    for(int i=0;i<ne;i++){
        scanf("%d %d %d",&E[i].u,&E[i].v,&E[i].cost);
    }


   Kruskal();
   printf("%d",ans);

   return 0;
}

测试数据1:

6 10 0
0 1 4
0 4 1
0 5 2
1 2 6
1 5 3
2 3 6
2 5 5
3 4 4
3 5 5
4 5 3

输出结果1:15  

测试数据2:

6 10
0 1 4
0 4 1
0 5 2
1 2 1
1 5 3
2 3 6
2 5 5
3 4 5
3 5 4
4 5 3

测试结果2:11 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值