最小生成树——北极通讯网络

问题 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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值