最小生成树boruvka算法
算法内容
初始时, \(E'=\varnothing\) ,每个点是一个连通块。
记每个连通块的向其他连通块连的所有边中最小的一条边为 \(t\) 。
一轮操作可以分为以下几个步骤:
- 将每个连通块的 \(t\) 清除。
- 遍历每条边 \((u,v)\) ,如果 \(u,v\) 不在同一连通块内则用 \(w_{(u,v)}\) 更新其所在连通块的 \(t\) 。
- 如果所有连通块都没有 \(t\) ,那么我们已经找出了最终的 \(E'\) ,程序结束。否则,将连通块按最小边合并,进行下一轮操作。
因为每轮操作过后连通块数量至少减半,所以时间复杂度 \(O(m\log n)\)。
给出洛谷模板题代码
#include<bits/stdc++.h>
using namespace std;
const int mn=5005,mm=2e5+5;
int fa[mn];
int find(int x)
{
return (fa[x]==x)?x:fa[x]=find(fa[x]);
}
int t[mn];
int tid[mn];
struct edge
{
int u,v,w;
}a[mm];
int tot,ans,n,m;
void boruvka()
{
while(1)
{
// 1.clear t
for(int i=1;i<=n;i++)
{
t[i]=0x3f3f3f3f;
}
// 2.遍历边
for(int i=1;i<=m;i++)
{
int x=find(a[i].u);
int y=find(a[i].v);
if(x==y)continue;
else
{
if(t[x]>a[i].w)
{
t[x]=a[i].w;
tid[x]=y;
}
if(t[y]>a[i].w)
{
t[y]=a[i].w;
tid[y]=x;
}
}
}
// 3.加边加边加边
bool f=0;
for(int i=1;i<=n;i++)
{
if(i!=fa[i] || t[i]==0x3f3f3f3f)continue;
f=1;
tot++;
ans+=t[i];
fa[find(tid[i])]=i;
}
if(f==0)break;
}
if(tot!=n-1)printf("orz\n");
else printf("%d\n",ans);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
}
boruvka();
}

浙公网安备 33010602011771号