题目:
给出N个点的坐标,对它们建立一个最小生成树,代价就是连接它们的路径的长度,现要求总长度最小。N的值在100以内,坐标值在[-10000,10000].结果保留二位小数
样例输入:
5
0 0
0 1
1 1
1 0
0.5 0.5
样例输出:
2.83
思路:
用Kruskal算法加勾股定理,不懂Kruskal算法,可以看一下。
代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define d double
using namespace std;
int f[1000],n,t;
double ans,x,y,gg[1000][1000];
struct node//建邻接表用
{
double w,p,s;
}a[100001];
int find(int dep)//找根节点+路径压缩
{
if(f[dep]==dep)return dep;
else return f[dep]=find(f[dep]);
}
bool pc(node x,node y)//排序用
{
return x.s<y.s;//从小到大
}
void hb(int x,int y)//合并
{
int xx=find(x);
int yy=find(y);
if (xx<yy) f[xx]=f[yy];
else f[yy]=f[xx];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1;i<=n;i++)
{scanf("%lf%lf",&x,&y),gg[i][0]=x,gg[i][1]=y;}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
double xx=(double)(gg[i][0]-gg[j][0]);
double yy=(double)(gg[i][1]-gg[j][1]);
double jl=(double)sqrt(xx*xx+yy*yy);//勾股定理
a[++t]=(node){i,j,jl};//邻接表
}
int bian=0;//算法主体
sort(a+1,a+t+1,pc);
for(int i=1;i<=t;i++)
if(find(a[i].w)!=find(a[i].p))//如果不在一个集合
{
hb(a[i].w,a[i].p);//合并
ans+=a[i].s;//累加答案
bian++;//边数++
if(bian==n-1)//跳出
break;
}
printf("%.2lf",ans);//输出(保留两位小数)
}