返回顶部

Borůvka算法

模拟赛用到了,就来学一下。

根据 oi-wiki 上的讲解和抽象伪代码,我们可以什么也发现不了。但是这个动图却有极大的作用,于是偷过来了。

P3366 【模板】最小生成树

可以用 Prim 和 Kruskal 算法做,但是讲一讲 Borůvka 算法。

我们遍历每一条边,如果两个端点已经在同一个连通块里,直接弹掉,否则判断这条边是否为该连通块向外连出的权值最小边,进行更新,最后遍历一遍顶点,统计答案。

如果没有更新边的话说明已经达到最优状态,直接跳出循环。

code
#include<bits/stdc++.h>
using namespace std;
const int M=2e5+10;
const int N=5010;
struct abc{
    int x,y,w;
}bi[M];
int n,m,num,ans;
int fa[N],best[N];
bool cz=1,z[M];
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-'){
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x*f;
}
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline bool check(int i,int j){
    return (j==0)?1:((bi[i].w!=bi[j].w)?(bi[i].w<bi[j].w):(i<j));
}
int main(){
    n=read(); m=read();
    for(int i=1;i<=m;i++){
        bi[i]=(abc){read(),read(),read()};
    }
    for(int i=1;i<=n;i++){
        fa[i]=i;
    }
    while(cz){
        cz=0;
        memset(best,0,sizeof(best));
        for(int i=1;i<=m;i++){
            if(z[i]){
                continue;
            }
            int x=bi[i].x,y=bi[i].y;
            int fx=find(x),fy=find(y);
            if(fx!=fy){
                if(check(i,best[fx])){
                    best[fx]=i;
                }
                if(check(i,best[fy])){
                    best[fy]=i;
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(best[i]&&z[best[i]]==0){
                cz=1;
                ans+=bi[best[i]].w;
                num++;
                z[best[i]]=1;
                fa[find(bi[best[i]].x)]=find(bi[best[i]].y);
            }
        }
    }
    (num==n-1)?(cout<<ans<<'\n'):(cout<<"orz"<<'\n');
    return 0;
}
posted @ 2023-10-12 14:25  Airposs  阅读(63)  评论(2)    收藏  举报