最小生成樹之Kruskal演算法
阿新 • • 發佈:2018-12-13
簡介
求加權連通圖的最小生成樹的演算法
演算法描述
先按邊從小到大排序,從最短邊開始迴圈,若此邊連線的兩個點屬於不同的聯通分量則加入此邊並連線兩點(用並查集實現),直到加入n-1條邊。若m條邊都迴圈一遍了加入的邊仍不足n-1則此圖不能構成一棵樹。
證明
反證法可證:設目前的最短邊k連線定點u,v,若不連此邊,有兩種情況:1)後面的邊中沒有能使u,v聯通的,則k必選。2)不選k仍能構成一棵樹,這時連線邊k則構成一個環,此時可去掉除k外的一邊得到一棵權值和更小的樹,前後矛盾。
程式碼
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<cstring> using namespace std ; const int N=5000+1000 ; int n,m,tot,fa[N] ; struct T{int x,y,info;}Edge[200005]; int Find(int x){ return fa[x]==x?x:fa[x]=Find(fa[x]) ; } bool cmp(T a,T b){return a.info<b.info;} int Kruskal(){ int ans=0 ; for (int i=1;i<=n;i++) fa[i]=i ; for (int i=1;i<=m;i++) scanf("%d%d%d",&Edge[i].x,&Edge[i].y,&Edge[i].info) ; sort(Edge+1,Edge+1+m,cmp) ; for (int i=1;i<=m;i++){ int RX=Find(Edge[i].x), RY=Find(Edge[i].y) ; if ( RX!=RY ){ tot ++ ; fa[RX]=RY ; ans += Edge[i].info ; } } return tot==n-1?ans:-1 ; } int main(){ scanf("%d%d",&n,&m) ; int ans = Kruskal() ; if ( ans==-1 ) printf("orz") ; else printf("%d",ans ) ; }