问题描述
蒜头君和花椰菜君经常出难题考对方。一天,花椰菜君给蒜头君出了这样一道难题:花椰菜君在坐标系上随机画了 N 个点,然后让蒜头君给点之间连线,要求任意两点之间都是连通的,且所连的线段长度之和最小。聪明的你快来帮蒜头君解决一下吧。
输入格式
第一行输入一个整数 N(1≤N≤100),表示花椰菜君一共画了 N 个点。然后输入 N 行,每行输入两个整数 x,y(0≤x,y≤1,000),代表一个点的坐标。
输出格式
输出一行,输出一个实数,表示所连线段长度之和的最小值(结果四舍五入保留两位小数)。
样例输入
4
1 1
2 2
3 3
3 1
样例输出
4.24
using namespace std;
const int MAX_N = 101;
const int MAX_M = 10000;
struct edge {
int u, v;
double len;
} E[MAX_M];
bool cmp (edge a, edge b) {
return a.len < b.len;
}
int fa[MAX_N];
int get(int x) {
if (x == fa[x]) {
return x;
}
return fa[x] = get(fa[x]);
}
double kruskal(int n,int m){
double sum=0;
for(int i=1;i<=n;i++){
fa[i]=i;
}
sort(E,E+m,cmp);
for(int i=0;i<m;i++){
int fu = get(E[i].u);
int fv = get(E[i].v);
if(fu != fv){
fa[fv] = fu;
sum+=E[i].len;
}
}
return sum;
}
int main(){
vector<pair<int,int> > poi;
int n,m;
cin>>n;
m = n*(n-1);
int x,y;
for(int i=0;i<n;i++){
cin>>x>>y;
poi.push_back(make_pair(x,y));
}
int num =0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
int x1,x2,y1,y2;
x1 = poi[i].first;
y1 = poi[i].second;
x2 = poi[j].first;
y2 = poi[j].second;
double w = sqrt(pow(x1-x2,2)*1.00 + pow(y1-y2,2)*1.00);
if(i!=j){
E[num].u = i;
E[num].v = j;
E[num].len = w;
num++;
}
}
}
cout<<fixed<<setprecision(2)<<kruskal(n,num)<<endl;
return 0;
}