码迷,mamicode.com
首页 > 其他好文 > 详细

P3366 【模板】最小生成树(boruvka/sollin)

时间:2019-03-15 20:46:32      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:efi   操作   code   link   turn   problem   class   优先   amp   

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

 

P3366 【模板】最小生成树(boruvka/sollin)

标签:efi   操作   code   link   turn   problem   class   优先   amp   

原文地址:https://www.cnblogs.com/kafuuchino/p/10534127.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!