Farmer John最近得到了一些新的农场,他想新修一些道路使得他的所有农场可以经过原有的或是新修的道路互达(也就是说,从任一个农场都可以经过一些首尾相连道路到达剩下的所有农场)。有些农场之间原本就有道路相连。 所有N(1 <= N <= 1,000)个农场(用1..N顺次编号)在地图上都表示为坐标为(X_i, Y_i)的点(0 <= X_i <= 1,000,000;0 <= Y_i <= 1,000,000),两个农场间道路的长度自然就是代表它们的点之间的距离。现在Farmer John也告诉了你农场间原有的M(1 <= M <= 1,000)条路分别连接了哪两个农场,他希望你计算一下,为了使得所有农场连通,他所需建造道路的最小总长是多少。
* 第1行: 2个用空格隔开的整数:N 和 M
* 第2..N+1行: 第i+1行为2个用空格隔开的整数:X_i、Y_i * 第N+2..N+M+2行: 每行用2个以空格隔开的整数i、j描述了一条已有的道路, 这条道路连接了农场i和农场j
* 第1行: 输出使所有农场连通所需建设道路的最小总长,保留2位小数,不必做 任何额外的取整操作。为了避免精度误差,计算农场间距离及答案时 请使用64位实型变量
感觉这种爆范围的地方特别要小心,上次CF的某道题mod的时候都会爆int,比较坑....
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <string>
using namespace std;
const int maxn=1001;
int n,m;
struct node{
int x,y;
}a[maxn];
int fa[maxn*maxn];
int x,y;
struct kru{
int num1,num2;
double dist;
}f[maxn*maxn];
int tot=0;
double ans=0;
bool cmp(const kru &a,const kru &b){
return a.dist<b.dist?1:0;
}
double d(long long x1,long long y1,long long x2,long long y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int find(int x){
if(fa[x]==x) return x; else return fa[x]=find(fa[x]);
}
int main(){
freopen("roads.in","r",stdin);
freopen("roads.out","w",stdout);
//freopen("data.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
f[++tot].num1=x;
f[tot].num2=y;
f[tot].dist=0;
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++){
f[++tot].num1=i;
f[tot].num2=j;
f[tot].dist=d(a[i].x,a[i].y,a[j].x,a[j].y);
}
sort(f+1,f+tot+1,cmp);
int k=0;
for(int i=1;i<=tot;i++){
int u=f[i].num1;
int v=f[i].num2;
if(find(u)!=find(v)){
ans+=f[i].dist;
fa[find(u)]=find(v);
k++;
}
if(k==n-1) break;
}
printf("%.2f",ans);
return 0;
}