题目描述
Farmer John had just acquired several new farms! He wants to connect the farms with roads so that he can travel from any farm to any other farm via a sequence of roads; roads already connect some of the farms.
Each of the N (1 ≤ N ≤ 1,000) farms (conveniently numbered 1..N) is represented by a position (Xi, Yi) on the plane (0 ≤ Xi ≤ 1,000,000; 0 ≤ Yi ≤ 1,000,000). Given the preexisting M roads (1 ≤ M ≤ 1,000) as pairs of connected farms, help Farmer John determine the smallest length of additional roads he must build to connect all his farms.
给定 n 个点的坐标,第 i 个点的坐标为 (xi,yi),这 n 个点编号为 1 到 n。给定 m 条边,第 i 条边连接第 ui 个点和第 vi 个点。现在要求你添加一些边,并且能使得任意一点都可以连通其他所有点。求添加的边的总长度的最小值。
输入格式
* Line 1: Two space-separated integers: N and M
* Lines 2..N+1: Two space-separated integers: Xi and Yi
* Lines N+2..N+M+2: Two space-separated integers: i and j, indicating that there is already a road connecting the farm i and farm j.
第一行两个整数 n,m 代表点数与边数。
接下来 n 行每行两个整数 xi,yi 代表第 i 个点的坐标。
接下来 m 行每行两个整数 ui,vi 代表第 i 条边连接第 ui 个点和第 vi 个点。输出格式
* Line 1: Smallest length of additional roads required to connect all farms, printed without rounding to two decimal places. Be sure to calculate distances as 64-bit floating point numbers.
一行一个实数代表添加的边的最小长度,要求保留两位小数,为了避免误差, 请用 64 位实型变量进行计算。
输入输出样例
输入 #1复制
4 1 1 1 3 1 2 3 4 3 1 4输出 #1复制
4.00说明/提示
数据规模与约定
对于 100% 的整数,1≤n,m≤1000,1≤xi,yi≤10^6,1≤ui,vi≤n。
说明
Translated by 一只书虫仔。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,cnt;//cnt很重要!!!
double sum;//double!!!
pair<int,int> s[1000010];
pair<double,pair<int,int>> sn[1000010];//double!!!
int anc[1000010];
double juli(int i,int j){//!!!注意全用double 要不然会错点
return (double)(sqrt((double)(s[i].first-s[j].first)*(s[i].first-s[j].first)+(double)(s[i].second-s[j].second)*(s[i].second-s[j].second)));
}
int find(int x){//并查集模板
if(anc[x]!=x) anc[x]=find(anc[x]);
return anc[x];
}
void kruskal(){//模板 小改
for(int i = 1;i<=n;i++) anc[i]=i;
for(int i = 1;i<=cnt;i++){
int a=sn[i].second.first,b=sn[i].second.second;
double c=(double)sn[i].first;//double!!!
int t1=find(a),t2=find(b);
if(t1!=t2){
anc[t1]=t2;
sum+=c;
}
}
printf("%.2lf",sum);
}
int main(){
cin >> n >> m;
for(int i = 1;i<=n;i++){
int x,y;
cin >> x >> y;
s[i]={x,y};//存点坐标
}
for(int i = 1;i<=n;i++){
for(int j = i+1;j<=n;j++){
double z=juli(i,j);//计算每两点间距离,某点和它后面某点
sn[++cnt]={z,{i,j}};//cnt存有多少条边
}
}
for(int i = 1;i<=m;i++){
int u,v;
cin >> u >> v;
for(int j = 1;j<=cnt;j++){//找到对应边替换 u,v大小未知,需要区分两种情况
if(sn[j].second.first==u&&sn[j].second.second==v){
sn[j]={0,{u,v}};
}else if(sn[j].second.first==v&&sn[j].second.second==u){
sn[j]={0,{v,u}};
}
}
}
sort(sn+1,sn+cnt+1);//排序
kruskal();
return 0;
}