北极通讯网络(最小生成数,Kruskal算法)

17 篇文章 6 订阅
5 篇文章 0 订阅

时间限制: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;
            }
        }
    }
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旧林墨烟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值