Loading

洛谷P1991 无线通讯网(最小生成树性质+连通块)

题目描述

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

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

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

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

输入格式

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

输出格式

输出 wireless.out 中

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

输入输出样例

输入 #1 
2 4
0 100
0 300
0 600
150 750
输出 #1 
212.13

说明/提示

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

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

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

差不多是最小生成树裸题了...一开始没看到“直接或间接”,想了一晚上QnQ...有了这一句话,假设没有卫星电话这个条件,能看出来求的就是最小生成树的最大边。那么卫星电话是干啥用的呢?就是删边用的。当删除最小生成树的m条边后,最小生成树会被划分成m+1个树形区域(即连通块)。基于卫星电话的特性,两个连通块是可以用一组卫星电话连接的,所以s个卫星电话可以连接s个连通块,将最小生成树分成s个连通块需要删除s-1条边,而最小生成树共有p-1条边,因此跑Kruskal时,只需要统计前(s-1)-(p-1)=s-p条边里的最大值即可。

#include <bits/stdc++.h>
using namespace std;
int s,p;
int fa[505]={0};
struct point
{
    int num;
    double x;
    double y;
}po[505];
struct rec
{
    int x;
    int y;
    double z;
}edge[250005];
int tot=0;
bool cmp(rec a,rec b)
{
    return a.z<b.z;
}
int get(int x)
{
    if(x==fa[x])return x;
    return fa[x]=get(fa[x]);
}
double calc(double x1,double y1,double x2,double y2)//求两点间距离 
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double mmax(double a,double b)
{
    return a>b?a:b;
}
int main()
{
    cin>>s>>p;
    int i,j;
    for(i=1;i<=p;i++)fa[i]=i;
    for(i=1;i<=p;i++)
    {
        po[i].num=i;
        cin>>po[i].x>>po[i].y;
    }
    for(i=1;i<=p;i++)//先建立一个完全图,在完全图上跑 Kruskal
    {
        for(j=i;j<=p;j++)
        {
            double temp=calc(po[i].x,po[i].y,po[j].x,po[j].y);
            if(temp)
            {
                tot++;
                edge[tot].x=po[i].num;
                edge[tot].y=po[j].num;
                edge[tot].z=temp;
            }
        }
    }
    sort(edge+1,edge+tot+1,cmp);
    double ans=0;
    int cnt=0;
    for(i=1;i<=tot;i++)
    {
        if(cnt==p-s)break;//建立完前p-s条边时即可break 
        int x=get(edge[i].x);
        int y=get(edge[i].y);
        if(x==y)continue;
        fa[x]=y;
        cnt++;
        ans=mmax(ans,edge[i].z); 
    }
    printf("%.2lf",ans);
    return 0;
 } 

 

 

posted @ 2020-02-19 16:25  脂环  阅读(212)  评论(0编辑  收藏  举报