[USACO07DEC]道路建设Building Roads

题目传送门

关于Kruskal算法

Kruskal算法是一种用来查找最小生成树的算法,由Joseph Kruskal在1956年发表。用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪心算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。

sol

这是一道最小生成树模板题,据题意:为了使得所有农场连通,我选择用Kruskal来做,一开始,有些边已经存在,所以把它们的边权值赋为0

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
const int Maxn=1000001;
int n,m;
int xx[1010],yy[1010],f[1010],A,B;
struct node{
    int x;
    int y;
    double val; 
}a[Maxn];
bool cmp(node a,node b){//从小到大排序
    return a.val<b.val; 
}
int find(int x){//找祖先,并查集
    while(x!=f[x])x=f[x]=f[f[x]];
	return x;    
}
void union_set(int x,int y){//合并
    f[find(x)]=find(y);   
}
int main()
{   
    int cnt=0;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>xx[i]>>yy[i];//读入坐标
    for(int i=1;i<=n;i++)
        f[i]=i;//初始化,把每个点的父亲赋给自己
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++) {
            a[++cnt].x=i;//存边
            a[cnt].y=j;//同上
            a[cnt].val=(double)sqrt((double)(xx[i]-xx[j])*(xx[i]-xx[j])+(double)(yy[i]-yy[j])*(yy[i]-yy[j]));//计算欧几里得距离
        }
    for(int i=1;i<=m;i++){
        cin>>A>>B;
        a[++cnt].x=A;
        a[cnt].y=B;
        a[cnt].val=0.0;//如果边已经存在,就把它们的边权值赋为0
    }
    int top=0;
    double ans=0.0;//记住,ans要定义为double类型
    sort(a+1,a+cnt+1,cmp);
    for(int i=1;i<=cnt;i++){//Kruskal模板
        if(find(a[++top].x)!=find(a[top].y)){//如果它们的最先不一样,即不在同一个集合
            ans+=a[top].val;//加上边权值
            union_set(a[top].x,a[top].y);//把他们放到同一集合里
        }
    }
    printf("%.2lf",ans);
    return 0;
}//完结撒花
原文地址:https://www.cnblogs.com/qzwer/p/12940275.html