这题是典型的二分答案
一开始用最小生成树做,用S(卫星电话)把最大边删去,发现并不是最优解。
二分枚举D,小于等于D的边才可以“发挥作用”,用并查集计算连通分量的个数,
只有连通分量的个数小于等于S时,才认为可行。
*******************************************
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define pii pair<int,int>
#define MAXV 505
#define MAXE 250005
using namespace std;
struct edge{
int u,v;
double cost;
};
edge e[MAXE];
int S,P,E;
double D;
pii p[MAXV];
int f[MAXV];
int find(int x){
return (f[x]==x)?x:(f[x]=find(f[x]));
}
void init_find(){
for(int i=1;i<=P;i++){
f[i]=i;
}
}
void lik(int x,int y){
x=find(x),y=find(y);
if(x!=y){
f[x]=y;
}
}
bool comp(const edge &e1,const edge &e2){
return (e1.cost<e2.cost);
}
int check(){
init_find();
for(int i=1;i<=E;i++){
if(e[i].cost<=D){
lik(e[i].u,e[i].v);
}
}
int cnt=0;
int b[MAXV]={0};
for(int i=1;i<=P;i++){
int x=find(i);
if(!b[x]){
cnt++;
b[x]=1;
}
}
if(cnt>S){
return 0;
}
else{
return 1;
}
}
int main()
{
// freopen("data.in","r",stdin);
scanf("%d%d",&S,&P);
for(int i=1;i<=P;i++){
scanf("%d%d",&p[i].first,&p[i].second);
}
for(int i=1;i<=P;i++){
for(int j=i+1;j<=P;j++){
e[++E].u=i; e[E].v=j;
e[E].cost=sqrt((double)(p[i].first-p[j].first)*(p[i].first-p[j].first)+(double)(p[i].second-p[j].second)*(p[i].second-p[j].second));
}
}
sort(e+1,e+E+1,comp);
int l=1,r=E;
while(l<r){
int mid=l+(r-l)/2;
D=e[mid].cost;
if(check()){
r=mid;
}
else{
l=mid+1;
}
}
printf("%.2f\n",e[l].cost);
return 0;
}