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;
}

浙公网安备 33010602011771号