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:最小生成树 || 二分