1. 程式人生 > >P3366 【模板】最小生成樹(boruvka/sollin)

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

int fin targe http strong 合並操作 tdi 一個 ble

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)