P1991 无线通讯网[最小生成树]

Posted darkvalkyrie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1991 无线通讯网[最小生成树]相关的知识,希望对你有一定的参考价值。

题目描述

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

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

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

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

解析

点赞最多的那篇题解提到了瓶颈生成树,个人觉得造成了一些不必要的引入和证明(当然有兴趣者可以进行学习),实际上就用联通块也可以解释得很清楚,个人感觉也没有什么问题。

那就来口胡一下


首先回顾kruskal算法求解最小生成树步骤:其运用贪心思想,每次加入最小边,直到所有点连通为止。

首先根据题意,这个图是一个完全图,我们要找一个存在限制条件的生成树。

那么对于本题,我们首先考虑没有卫星电话存在的情况,显然就是一个裸的最小生成树。我们来看加边过程的具体意义:每次加入一条没有使用过的最短边,且该边没有连接两个已经连通的哨所,那么这条边会将至少两个哨所相连。

接着我们来看一个这样的例子:

假设此时P=5,S=3。

技术图片

假设当前1、2、3为用无线电连接的哨所,4、5是用卫星电话连接的哨所。此时我们只要在1、2、3中某一个加一个卫星电话,就可以使它们全部连通。


因此我们不妨考虑先放无线电,加最短边加到联通块数量减为S为止(不考虑卫星电话哨所之间的连边,如上图紫边),此时还剩下S-1个点,如果我们在这些点放置无线电,显然会造成总体不优,所以我们在这些点中放卫星电话。

那么还剩一个卫星电话没有放怎么办?我们在之前放下去的无线电中找出来一个点放,并且还要使得答案不变坏,那这样一来所有点也就连通了。

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 250010
#define MOD 2520
#define E 1e-12
#define IN freopen("data.in","r",stdin);
using namespace std;
inline int read()

    int f=1,x=0;char c=getchar();
    while(c<'0'||c>'9')if(c=='-')f=-1;c=getchar();
    while(c>='0'&&c<='9')x=x*10+c-'0';c=getchar();
    return x*f;

struct node
    int x,y;
    double val;
    bool operator<(const node a)const
        return val<a.val;
    
g[N];
struct dat
    int x,y;
a[N];
inline double fun(int x1,int y1,int x2,int y2)return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
int s,p,fa[N];
inline int get(int x)return x==fa[x]?x:get(fa[x]);
inline void merge(int x,int y)

    x=get(x),y=get(y);
    if(x!=y) fa[x]=y;

int main()

    s=read(),p=read();
    for(int i=1;i<=p;++i)
        a[i].x=read(),a[i].y=read(),fa[i]=i;
    int cnt=0;
    for(int i=1;i<=p;++i)
        for(int j=i+1;j<=p;++j)
            double z=fun(a[i].x,a[i].y,a[j].x,a[j].y);
            g[++cnt].x=i,g[cnt].y=j,g[cnt].val=z;
        
    sort(g+1,g+cnt+1);
    double ans=0;
    int tot=p;
    for(int i=1;i<=cnt;++i)
        int x=get(g[i].x),y=get(g[i].y);
        if(x==y) continue;
        if(tot==s) break;
        tot--;
        merge(x,y);
        ans=g[i].val;
    
    printf("%.2lf\\n",ans);
    return 0;

以上是关于P1991 无线通讯网[最小生成树]的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P1991 无线通讯网 Label:最小生成树 || 二分

P1991 无线通讯网kruskal

图论——最小生成树①

(最小生成树/最小瓶颈生成树) 2017武汉现场赛 - Wifi Relay

P1991 无线通讯网

hdu 2349 最小生成树