问题 B: 北极通讯网络
时间限制: 1 Sec 内存限制: 128 MB
提交: 17 解决: 7
[提交][状态][讨论版][命题人:add_xiezhenghao]
题目描述
北极的某区域共有n座村庄(1≤n≤500),每座村庄的坐标用一对整数(x,y)表示,其中0≤x,y≤10000。为了加强联系,决定在村庄之间建立通讯网络。通讯工具可以是无线电收发机,也可以是卫星设备。所有的村庄都可以拥有一部无线电收发机, 且所有的无线电收发机型号相同。但卫星设备数量有限,只能给一部分村庄配备卫星设备。
不同型号的无线电收发机有一个不同的参数d,两座村庄之间的距离如果不超过d就可以用该型号的无线电收发机直接通讯,d值越大的型号价格越贵。拥有卫星设备的两座村庄无论相距多远都可以直接通讯。
现在有k台(1≤k≤100)卫星设备,请你编写一个程序,计算出应该如何分配这k台卫星设备,才能使所有的无线电收发机的d值最小,并保证每两座村庄之间都可以直接或间接地通讯。
输入
第一行包括两个整数n、k,表示村庄的数量和卫星设备的数量。
之后的n行,输入xi,yi,表示第i个村庄的坐标。
输出
输出一个数,代表d的最小值。输出保留两位小数。
样例输入
3 2 10 10 10 0 30 0
样例输出
10.00
k个村庄装上卫星设备后可以看成1个点,那么只需要求这(n-k+1)个点和(n-k)条边所构成的最小生成树
利用Kruskal算法,只需要进行(n-k)次操作,最后一次操作时加入生成树的边的权值就是所求的d
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
int n,k,m,fa[505],x[505],y[505];
double d;
struct node//存储每条边的两个端点和距离
{
int a,b;
double distance;
}v[250000];
double dis(int ax,int ay,int bx,int by)//求两点之间距离
{
return sqrt((ax-bx)*(ax-bx)+(ay-by)*(ay-by));
}
int cmp(node n1,node n2)//按边的权值从小到大排序
{
return n1.distance<n2.distance;
}
int getfather(int x)//求父亲节点,并查集
{
if(fa[x]==x)return x;
fa[x]=getfather(fa[x]);
return fa[x];
}
void kruskal()//kruskal核心程序
{
int f1,f2,num1=0;
for(int i=1;i<=n;i++)//初始化每个点为一个集合
fa[i]=i;
for(int i=1;i<=m;i++)
{
f1=getfather(v[i].a);
f2=getfather(v[i].b);
if(f1!=f2)
{
fa[f1]=f2;//合并两个不同的集合
num1++;
if(num1==n-k)//放到第n-k条边
{
d=v[i].distance;//记录边的权值
break;//退出
}
}
}
}
int main()
{
cin>>n>>k;
if(k>=n)//每个村庄一台,d为0
{
cout<<"0.00"<<endl;
return 0;
}
if(k==0)k=1;
m=1;
for(int i=1;i<=n;i++)//输入每个村庄的坐标
cin>>x[i]>>y[i];
for(int i=1;i<=n;i++)//求出每条边边权和端点,m记录边数
for(int j=i+1;j<=n;j++)
{
v[m].a=i;
v[m].b=j;
v[m].distance=dis(x[i],y[i],x[j],y[j]);
m++;
}
m--;
sort(v+1,v+1+m,cmp);
kruskal();
cout.precision(2);
cout<<fixed<<d<<endl;
return 0;
}