时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
北极的某区域共有n座村庄,每座村庄的坐标用一对整数(x,y)表示。为了加强联系,决定在村庄之间建立通讯网络。通讯工具可以是无线电收发机,也可以是卫星设备。所有的村庄都可以拥有一部无线电收发机,且所有的无线电收发机型号相同。但卫星设备数量有限,只能给一部分村庄配备卫星设备。
不同型号的无线电收发机有一个不同的参数d,两座村庄之间的距离如果不超过d就可以用该型号的无线电收发机直接通讯,d值越大的型号价格越贵。拥有卫星设备的两座村庄无论相距多远都可以直接通讯。
现在有k台卫星设备,请你编一个程序,计算出应该如何分配这k台卫星设备,才能使所拥有的无线电收发机的d值最小,并保证每两座村庄之间都可以直接或间接地通讯。
例如,对于下面三座村庄:
其中|AB|=10,|BC|=20,|AC|=10*sqrt(5)≈22.36
如果没有任何卫星设备或只有1台卫星设备(k=0或k=1),则满足条件的最小的d=20,因为A和B,B和C可以用无线电直接通讯;而A和C可以用B中转实现间接通讯(即消息从A传到B,再从B传到C);
如果有2台卫星设备(k=2),则可以把这两台设备分别分配给B和C,这样最小的d可取10,因为A和B之间可以用无线电直接通讯;B和C之间可以用卫星直接通讯;A和C可以用B中转实现间接通讯。
如果有3台卫星设备,则A,B,C两两之间都可以直接用卫星通讯,最小的d可取0。
输入描述:
第一行为由空格隔开的两个整数n,k;
第2∼n+1行,每行两个整数,第i行的xi,yi表示第i座村庄的坐标(xi,yi )。
输出描述:
一个实数,表示最小的d值,结果保留2位小数。
示例1
输入
3 2
10 10
10 0
30 0
输出
10.00
解题思路:
一、Kruskal算法思路:
1.算出各条路径,并由路径长度递增排序
2. 遍历路径,若没有连接则连接,判断连接问题可以用并查集实现,若两点不在一个集合内则没有连接,反则连接
3. 按照以上方法构建出的路径都是连接的最短路径
二、有了Kruskal算法的基础则看思路:
1.首先,你可以把原始所有点都看作集合,题目成立的条件是:用无线电连接集合后,每个集合都分配一个卫星即可相互通信。即卫星个数须等于集合个数,我们用并查集可以实现集合的查询和合并,卫星是零时等价于1,注意一下就行了。
不理解欢迎留言评论哦
代码:
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cmath>
using namespace std;
struct Side
{
int x,y;
double d;
}side[250000];//题目没给数据范围,乱开的
bool cmp(Side p,Side q)
{
return p.d<q.d;
}
int f[10000];
int find(int n)//查并集
{
if(n!=f[n])return f[n]=find(f[n]);
return n;
}
int main()
{
int c[10000][2],n,m,i,j,n1=0,ans=0;
for(i=0;i<10000;i++)
f[i]=i;
cin>>n>>m;
if(n<=m)//提早结束
{
cout<<'0'<<endl;
return 0;
}
if(m==0)m=1;//0和1的作用是相同的,只有一台机器就是没用的
for(i=0;i<n;i++)
cin>>c[i][0]>>c[i][1];
for(i=1;i<n;i++)//Kruskal算法
for(j=0;j<i;j++)
{
side[n1].x=i;
side[n1].y=j;
side[n1++].d=sqrt(pow(c[i][0]-c[j][0],2)+pow(c[i][1]-c[j][1],2));
}
sort(side,side+n1,cmp);
for(i=0;i<n1;i++)
{
// cout<<side[i].x<<' '<<side[i].y<<' '<<side[i].d<<endl;
int a=find(side[i].x);
int b=find(side[i].y);
if(a!=b)
{
f[a]=b;
ans++;
if(ans==n-m)
{
cout<<setiosflags(ios::fixed)<<setprecision(2)<<side[i].d;
break;
}
}
}
}