无线通讯网(最小生成树经典问题)——洛谷P1991

无线通讯网(最小生成树经典问题)——洛谷P1991

题目描述

国防部计划用无线网络连接若干个边防哨所。2 种不同的通讯技术用来搭建无线网络;

每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。

任意两个配备了一条卫星电话线路的哨所(两边都ᤕ有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过 D D D,这是受收发器的功率限制。收发器的功率越高,通话距离 D D D 会更远,但同时价格也会更贵。

收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个 D D D。你的任务是确定收发器必须的最小通话距离 D D D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。

输入格式

从 wireless.in 中输入数据第 1 行,2 个整数 S S S P P P S S S 表示可安装的卫星电话的哨所数, P P P 表示边防哨所的数量。接下里 P P P 行,每行两个整数 x , y x,y xy 描述一个哨所的平面坐标 ( x , y ) (x, y) (x,y),以 km 为单位。

输出格式

输出 wireless.out 中

第 1 行,1 个实数 D D D,表示无线电收发器的最小传输距离,精确到小数点后两位。

样例 #1

样例输入 #1

2 4
0 100
0 300
0 600
150 750

样例输出 #1

212.13

提示

对于 20 % 20\% 20% 的数据: P = 2 , S = 1 P = 2,S = 1 P=2S=1

对于另外 20 % 20\% 20% 的数据: P = 4 , S = 2 P = 4,S = 2 P=4S=2

对于 100 % 100\% 100% 的数据保证: 1 ≤ S ≤ 100 1 ≤ S ≤ 100 1S100 S < P ≤ 500 S < P ≤ 500 S<P500 0 ≤ x , y ≤ 10000 0 ≤ x,y ≤ 10000 0x,y10000

题解/启示

  • 这一题粗看可以通过二分法实现,但仔细阅读题意后可以发现使用最小生成树更符合题意,特别是这句**“使得每一对哨所之间至少有一条通话路径(直接的或者间接的)”。可以看出符合最小生成树**的定义,那么再结合题意的卫星电话概念,为了确定最小距离,初步可以确定采用贪心的思想把最大的边给到卫星电话。

  • 那么最大的边给到卫星电话如何具体实现?我一开始是想整个图的最大的边给到卫星电话,但是这个思路不正确,最小生成树不一定用到这些边,那便应该是最小生成树的最大边。思路到这,发现其与kruskal思想非常契合,那么我们就可以在kruskal中做文章。

  • 还有一个是对题目概念要理解透,一开始我认为去掉的最大边的两个顶点都要有卫星电话,实际上还是没体会到最小生成树的间接思想,看图说话:

    在这里插入图片描述

    第一:假如在对AE都加上卫星电话后,为了去掉CD的边,我还需要在CD都安装卫星电话吗?答案是不需要,只需要给D卫星电话,D——A——C,即D与A卫星连接,AC正常连接,这样CD也是连接的。要理解透最小生成树的间接思想。

AC代码

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string.h>
#include <math.h>
#include<iomanip>
using namespace std;
typedef int ll;
typedef double dd;
typedef pair<ll, ll> pp;
struct node
{
    ll v1, v2;
    dd w;
    friend bool operator<(node a, node b)
    {
        return a.w > b.w; //小顶堆
    }
};
struct node2//实际上不需要这个,只需要在kruskal过程跳过最后s-1步即可,我懒得改了
{
    ll v1, v2;
    dd w;
    friend bool operator<(node2 a, node2 b)
    {
        return a.w < b.w; //大顶堆
    }
};
dd res = 0;
const ll maxn = 1e4 + 10;
ll s, p;
pp inc[maxn];
ll fa[maxn], wt[maxn],vex[maxn];
/* bool cmp(const node& a,const node& b)
{
    return a.w < b.w;
} *///不能用这个排序优先队列
void init()
{
    for (int i = 1; i <= p; i++)
    {
        fa[i] = i;
        wt[i] = 1;
    }
}
ll find(ll x)
{
    if (fa[x] == x)
        return x;
    return fa[x] = find(fa[x]);
}
void unite(ll a, ll b){
    ll f1 = find(a);
    ll f2 = find(b);
    if(f1 == f2) return;
    if(wt[f1] >= wt[f2])
    {
        fa[f2] = f1;
    }
    else{
        fa[f1] = f2;
    }
    if(wt[f1] == wt[f2]) {
        wt[f1]++;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> s >> p;
    priority_queue<node2> q;
    priority_queue<node> cost;
    for (int i = 1; i <= p; i++)
    {
        cin >> inc[i].first >> inc[i].second;
        for (int j = i - 1; j >= 1; j--)
        {
            dd w = sqrt((inc[i].first - inc[j].first)*(inc[i].first - inc[j].first) + (inc[i].second - inc[j].second)*(inc[i].second - inc[j].second));
            cost.push(node{i, j, w});
        }
    }
    init();
    while(!cost.empty())
    {
        node tmp = cost.top();cost.pop();
        if(find(tmp.v1) == find(tmp.v2)){
            continue;
        }
        unite(tmp.v1,tmp.v2);
        q.push(node2{tmp.v1,tmp.v2,tmp.w});
    }
    for(int j = 1; j <= s-1; j ++)
    {
        q.pop();
    }
    cout << setiosflags(ios::fixed) << setprecision(2) <<q.top().w <<endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值