最小生成树boruvka算法

算法内容

初始时, \(E'=\varnothing\) ,每个点是一个连通块。

记每个连通块的向其他连通块连的所有边中最小的一条边为 \(t\)

一轮操作可以分为以下几个步骤:

  1. 将每个连通块的 \(t\) 清除。
  2. 遍历每条边 \((u,v)\) ,如果 \(u,v\) 不在同一连通块内则用 \(w_{(u,v)}\) 更新其所在连通块的 \(t\)
  3. 如果所有连通块都没有 \(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();

}
posted @ 2025-03-15 09:56  ikusiad  阅读(48)  评论(0)    收藏  举报