题目传送门
关于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;
}//完结撒花