【题目描述】
国防部计划用无线网络连接若干个边防哨所。2种不同的通讯技术用来搭建无线网络;每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。
任意两个配备了一条卫星电话线路的哨所(两边都拥有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过D,这是受收发器的功率限制。收发器的功率越高,通话距离D会更远,但同时价格也会更贵。
收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个D。
你的任务是确定收发器必须的最小通话距离D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。
【输入格式】 wireless.in
第1行:2个整数S(1<=S<=100)和P(S<P<=500),S表示可安装的卫星电话的哨所数,P表示边防哨所的数量。
接下里P行,每行描述一个哨所的平面坐标(x,y),以km为单位,整数,0<=x,y<=10000。
【输出格式】 wireless.out
第1行:1个实数D,表示无线电收发器的最小传输距离。精确到小数点后两位。
【样例输入】
2 4
0 100
0 300
0 600
150 750
【样例输出】
212.13
数据范围
对于20%的数据 P=2,S=1
对于另外20%的数据 P=4,S=2
对于100%的数据 1<=S<=100,S<P<=500题解
并查集+二分。二分出当前的最小传输距离d,将边重置,用并查集看看有多少个联通块,若联通块数量<=s , 则当前的d比较优。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,s,zz;
struct dian{int x,y;} d[502];
struct bian{int x,y;double v;} e[260002];
int fa[502];
double ans=1e10;
void init()
{
scanf("%d%d",&s,&n);
for(int i=1;i<=n;i++) scanf("%d%d",&d[i].x,&d[i].y);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{zz++; e[zz].x=i; e[zz].y=j;
e[zz].v=sqrt((d[i].x-d[j].x)*(d[i].x-d[j].x)+(d[i].y-d[j].y)*(d[i].y-d[j].y));
}
}
bool kp(const bian &i,const bian &j)
{return i.v>j.v;}
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
bool work(int w)
{
int ct=n;
for(int i=1;i<=zz;i++)
{if(e[i].v<=e[w].v)
{int r1=find(e[i].x),r2=find(e[i].y);
if(r1!=r2) {fa[r1]=r2; ct--;}
}
}
//printf("%d %d\n",w,ct);
if(ct<=s) {ans=min(ans,e[w].v); return true;}
else return false;
}
void doit()
{
sort(e+1,e+zz+1,kp);
/*for(int i=1;i<=zz;i++) printf("%d %d %.2lf\n",e[i].x,e[i].y,e[i].v);
system("pause");*/
int l=1,r=zz;
while(l<=r)
{for(int i=1;i<=n;i++) fa[i]=i;
int mid=(l+r)>>1;
if(work(mid)) l=mid+1;
else r=mid-1;
}
}
int main()
{
freopen("wireless.in","r",stdin);
freopen("wireless.out","w",stdout);
init();
doit();
printf("%.2lf\n",ans);
return 0;
}