3.41
题意:给你n个点,求能把这n个点连起来所用的最少墨水
最小生成树的模板题:一旦两个点已经被连线,那么再出现的时候就不能再连,否则会浪费墨水,这时就用到了并查集的思想,一旦两个点的父亲节点相同,则他们之间便有了线,不用再连。而n个点最少需要n-1条边来连接。注意POJ的题目能用c++就不要用G++,因为莫名其妙就会出错
请看代码:
#include <iostream>
#include <math.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
struct node
{
double x,y;
};
struct code
{
int x,y;
double v;
};
bool cmp(code a,code b)
{
return a.v<b.v;
}
int const N=110;
node a[N];
int father[N];
code b[N*N];
int Find(int a)
{
int b=a;
while(b!=father[b]) b=father[b];
while(a!=father[a])
{
int x=father[a];
father[a]=b;
a=x;
}
return b;
}
void Union(int x,int y)
{
int fx=Find(x);
int fy=Find(y);
if(fx!=fy) father[fx]=fy;
}
int main()
{
int m;
while(~scanf("%d",&m))
{
for(int i=1;i<=m;i++) scanf("%lf %lf",&a[i].x,&a[i].y);
for(int i=1;i<=m;i++) father[i]=i;
int p=1;
for(int i=1;i<m;i++)
{
for(int j=i+1;j<=m;j++)
{
b[p].x=i;
b[p].y=j;
b[p].v=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
p++;
}
}
sort(b+1,b+p,cmp);
double ans=0;
int k=0;
for(int i=1;i<p;i++)
{
if(Find(b[i].x)==Find(b[i].y)||k==m-1) continue;
Union(b[i].x,b[i].y);
ans+=b[i].v;
k++;
}
printf("%.2lf\n",ans);
}
return 0;
}