洛谷P1991 无线通讯网
题目描述
国防部计划用无线网络连接若干个边防哨所。2 种不同的通讯技术用来搭建无线网络;
每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。
任意两个配备了一条卫星电话线路的哨所(两边都有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过 D,这是受收发器的功率限制。收发器的功率越高,通话距离 D 会更远,但同时价格也会更贵。
收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个 D。你的任务是确定收发器必须的最小通话距离 D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。
输入格式
输入数据第1行,2个整数S和P,S表示可安装的卫星电话的哨所数P表示边防哨所的数量。接下里P行,每行两个整数x,y描述一个哨所的平面坐标(x, y),以km为单位。
输出格式
第 1 行,1 个实数 D,表示无线电收发器的最小传输距离,精确到小数点后两位。
输入输出样例
输出 #1
2 4
0 100
0 200
0 600
150 750
输出 #1
212.13
说明/提示
对于 20% 的数据:P=2,S=1
对于另外 20% 的数据:P=4,S=2
对于 100% 的数据保证:1≤S≤100,S<P≤500,0≤ x,y≤10000。
解题思路
写这道题之前刚做了【[JSOI2010]部落划分】,这两题在某种程度上很相似。将所有的哨所划分为S块,并使得每块哨所中的最远距离尽可能的小。数据规模较小,可以暴力求出每条边的边权,从小到大排列好,用并查集维护,也就是一个最小生成树,Kruskal算法可以秒了。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=510;
int x[maxn],y[maxn];
struct Edge{
int x,y;
double dis;
}Ed[maxn*maxn];
double getDistance(int a,int b){
return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
bool cmp(Edge a,Edge b){return a.dis<b.dis;}
int F[maxn],siz[maxn];
void Init_Set(){
for(int i=0;i<maxn;i++){
F[i]=i; siz[i]=0;
}
}
int Find(int x){
if(F[x]==x) return x;
return F[x]=Find(F[x]);
}
void Union_Set(int x,int y){
if((x=Find(x))==(y=Find(y))) return;
if(siz[x]<siz[y]) F[x]=y;
else if(siz[x]>siz[y]) F[y]=x;
else{
F[x]=y; siz[y]++;
}
}
int main(){
int s,p;
cin>>s>>p;
for(int i=1;i<=p;i++){
cin>>x[i]>>y[i];
}
int cnt=0;
for(int i=1;i<p;i++){
for(int j=i+1;j<=p;j++){
Ed[++cnt].dis=getDistance(i,j);
Ed[cnt].x=i;
Ed[cnt].y=j;
}
}
sort(Ed+1,Ed+cnt+1,cmp);
int t=0;
Init_Set();
double minn;
for(int i=0;i<=cnt;i++){
if(t==p-s) break;
if(Find(Ed[i].x)!=Find(Ed[i].y)){
Union_Set(Ed[i].x,Ed[i].y);
t++;
minn=Ed[i].dis;
}
}
printf("%.2f\n",minn);
return 0;
}