最小生成树Boruvka算法

Boruvka

复杂度

O ( E l o g V ) O(ElogV) O(ElogV)

原理

根据并查集的思想,一开始所有点看做独立子集,每次遍历边找到两个集合之间连接的最短边,不断扩大集合直到所有点合并为一个集合。由于每次循环迭代时,每棵树都会合并成一棵较大的子树,因此每次循环迭代都会使子树的数量至少减少一半,因此时间复杂度非常稳定

图示

在这里插入图片描述

步骤

  1. 使用数组 b e s t best best记录每个集合的最短邻边的点,如果有多个权值相同的邻边,那么取下标较小的
  2. 循环主体:
    • 遍历所有的边,也就是对所有的连通块找不在集合中的,到达其他连通块的最短边,其下标保存在 b e s t best best数组中
    • 遍历所有的点,将合法且未访问的边加入最小生成树

代码

const int maxn=2e5+10;
const int maxm=1e6+10;

struct node{
    int u,v,w;
}edge[maxm];

int f[maxn],best[maxn];
bool vis[maxn];
int n,m;

int Find(int x){
    return f[x]==x?x:f[x]=Find(f[x]);
}

bool cmp(int x,int y){   //判断两边权值及下标大小
    if(y==0) return 1;
    if(edge[x].w!=edge[y].w) return edge[x].w<edge[y].w;
    return x<y;
}

void init(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
    for(int i=1;i<=n;i++) f[i]=i;
}

int Boruvka(){
    memset(vis,0,sizeof vis);
    int ans=0,cnt=0;
    bool ok=1;
    while(ok){
        ok=0;
        memset(best,0,sizeof best);
        //遍历所有边
        for(int i=1;i<=m;i++) if(!vis[i]){
            int x=Find(edge[i].u),y=Find(edge[i].v);
            if(x==y) continue;
            if(cmp(i,best[x])) best[x]=i;
            if(cmp(i,best[y])) best[y]=i;
        }
		//遍历所有点
        for(int i=1;i<=n;i++) if(best[i] && !vis[best[i]]){
            ok=1,cnt++,ans+=edge[best[i]].w;
            vis[best[i]]=1;
            int x=Find(edge[best[i]].u),y=Find(edge[best[i]].v);
            f[x]=y;
        }
    }
    if(cnt==n-1) return ans;
    return -1;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值