zoukankan      html  css  js  c++  java
  • P3366 【模板】最小生成树(boruvka/sollin)

    P3366 【模板】最小生成树

    boruvka/sollin

    复杂度$O(mlogn)$

    简要说明一下过程

    引入一个数组$link[i]$表示连通块$i$下一步可更新的最短的边的编号

    1.每次枚举所有边,如果边连接的2个点$(u,v)$不属于同连通块,那么更新$link[find(u)],link[find(v)]$(find(u)表示$u$所属的连通块)

    2.枚举所有连通块,将$link[i]$两边的连通块合并。

    3.如果第2步中有合并操作,则跳到1

    注意更新$link[i]$,当比较的两条边权值相同时,要有确定的大小顺序,通常优先取编号小的。

    #include<cstdio>
    #include<cstring>
    #define N 5005
    #define M 200005
    int n,m,k,ans,fa[N],link[N],U[M],V[M],W[M]; bool vis[M];
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline bool fc(int x,int y){return W[x]==W[y]?x<y:W[x]<W[y];}
    void boruvka(){
        for(bool ok=1;ok;){
            memset(link,0,sizeof(link)); ok=0;
            for(int i=1;i<=m;++i) if(!vis[i]){
                int r1=find(U[i]),r2=find(V[i]);
                if(r1==r2) continue;
                if(fc(i,link[r1])) link[r1]=i;
                if(fc(i,link[r2])) link[r2]=i;
            }
            for(int i=1;i<=n;++i) if(!vis[link[i]]&&link[i]){
                vis[link[i]]=ok=1; ans+=W[link[i]]; ++k;
                fa[find(U[link[i]])]=find(V[link[i]]);
            }
        }
    }
    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",&U[i],&V[i],&W[i]);
        W[0]=1e9; boruvka();
        k==n-1 ? printf("%d",ans):puts("orz");
        return 0;
    }
  • 相关阅读:
    mysql安装
    Python中的 _init__和 _new__的区别
    MySQL系列
    彻底解决编码问题
    人生三问之前后端分离是什么鬼?
    什么是内存泄漏?什么是内存溢出?
    目录
    虚拟环境的使用
    如何为Redis中list中的项设置过期时间
    Redis分布式锁的python实现
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10534127.html
Copyright © 2011-2022 走看看