【模板】最小生成树(kruscal)

//洛谷P3366

(其中所应用的并查集原理请见http://www.cnblogs.com/XjzLing/p/7943363.html

这里选用Kruscal的方法:先将每一个点用并查集记录它们的祖先,用fa[i]来表示

然后将边按照权重,从小到大排序,这里选用sort的cmp。

然后,从小到大遍历边权,如果遍历到一条边的所连的两个结点不在同一集合,就将这两个点连上,ans+=G[i].val即可。

等连到n-1条边时,该图已经成为一颗树,即输出答案

#include<algorithm>
#include<iostream>
#include<cstdio>
#define maxn 200000 + 10
using namespace std;
int n,m,ans,num;
int fa[maxn];
struct edge{
    int frm,to,val;
}G[maxn];
//记录边的信息:起点,终点,权 
void init(){
    for(int i=1;i<=n;i++) fa[i]=i;
}//并查集预处理 
bool cmp(edge a,edge b){
    return a.val<b.val;
}// 用于sort的cmp函数 
int find(int x){
    if(x==fa[x]) return x;
    else return fa[x]=find(fa[x]);
}//并查集找祖先 
bool merge(edge a){
    if(find(a.frm)!=find(a.to)){
        fa[fa[a.to]]=find(a.frm);
        return true;
    }
    return false;
}//并查集连边 
int main(){
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=m;i++) scanf("%d%d%d",&G[i].frm,&G[i].to,&G[i].val);
    sort(G,G+m,cmp);//将边权从小到大排序 
    for(int i=1;i<=m && num<n-1;i++)
        if(merge(G[i])){
            ans+=G[i].val;
            num++;
        }//Kruscal操作 
    if(num==n-1) printf("%d",ans);
    else printf("orz");
    return 0;
}

 

posted @ 2017-12-01 16:47  XjzLing  阅读(225)  评论(0编辑  收藏  举报