最小生成树裸题。
这里讲一下两点之间的直线距离怎么算:
\[\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}\]
然后只要将每两个点之间的距离算出来,已有的边距离为\(0\),跑一遍最小生成树就\(OK\)了。
\(Code:\)
#pragma GCC diagnostic error "-std=c++11"
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
template<class T>void r(T &a)
{
T s=0,w=1;a=0;char ch=getc(stdin);
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getc(stdin);}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getc(stdin);}
a=w*s;
}
template<class T,class... Y>void r(T& t,Y&... a){r(t);r(a...);}
int n,m;
struct edge
{
int u,v;
double w;
}e[1000010];
struct bcj
{
int father[1010];
void start(int n)
{for(int i=0;i<=n;i++)father[i]=i;}
int find(int x)
{if(father[x]!=x)father[x]=find(father[x]);return father[x];}
void unionn(int x,int y)
{x=find(x);y=find(y);if(x!=y)father[y]=x;}
bool judge(int x,int y)
{if(find(x)==find(y))return true;return false;}
};
bool cmp(edge a,edge b)
{
return a.w<b.w;
}
void kruskal()
{
bcj uf;
int cnt=0;
double ans=0.0;
sort(e+1,e+1+m,cmp);
uf.start(n);
for(int i=1;i<=m;i++)
{
if(!uf.judge(e[i].u,e[i].v))
{
cnt++;
ans+=e[i].w;
uf.unionn(e[i].u,e[i].v);
}
if(cnt==n-1)break;
}
printf("%0.2lf",ans);
}
int x[1010],y[1010];
double jl(int i,int j)
{
return (double)sqrt((double)(x[i]-x[j])*(double)(x[i]-x[j])+(double)(y[i]-y[j])*(double)(y[i]-y[j]));
//这里必须强制赋值为double,不然会有4个点WA
}
int main()
{
int q;
r(n,q);
for(int i=1;i<=n;i++)
r(x[i],y[i]);
for(int i=1;i<=q;i++)
{
m++;
r(e[m].u,e[m].v);
e[m].w=0.0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)
{
m++;
e[m]=(edge){i,j,jl(i,j)};
}
kruskal();
return 0;
}