题意为给定一堆坐标,以及n个可以使距离变为0的路径条数(放卫星),求一个生成树,使得最大的边最小。
由最小生成树的性质我们可以知道,对于每一条边,一定是第x大里最小的,否则一定会有一个边来替换,这个就不是生成树了。所以我们可以跑一遍最小生成树,然后第n大的边就是答案了。
下附AC代码。
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#define maxn 250005
using namespace std;
struct po
{
double x,y;
}pos[505];
double finddis(int i,int j)
{
return sqrt((pos[i].x-pos[j].x)*(pos[i].x-pos[j].x)+(pos[i].y-pos[j].y)*(pos[i].y-pos[j].y));
}
int q,m,n,cnt,cnt1;
int u[maxn],e[maxn],temp[maxn],fa[maxn];
double tt[maxn];
double w[maxn];
double cmp(int i,int j)
{
return w[i]<w[j];
}
int find(int x)
{
return fa[x]==x? x : fa[x]=find(fa[x]);
}
double kruskal()
{
for(int i=1;i<=m;i++)
fa[i]=i;
for(int i=1;i<=cnt;i++)
temp[i]=i;
sort(temp+1,temp+cnt+1,cmp);
double ans=0;
for(int i=1;i<=cnt;i++)
{
int t=temp[i];
int x=find(u[t]);
int y=find(e[t]);
if(x==y) continue;
ans+=w[t];
cnt1++;
tt[cnt1]=w[t];
fa[x]=y;
}
return ans;
}
int main()
{
scanf("%d",&q);
while(q--)
{
cnt=0;
cnt1=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%lf%lf",&pos[i].x,&pos[i].y);
}
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
if(i!=j)
{
cnt++;
double d=finddis(i,j);
u[cnt]=i;
e[cnt]=j;
w[cnt]=d;
}
kruskal();
printf("%.2f\n",tt[cnt1-n+1]);
}
}