poj 2349

题目概述

有P个前哨站在平面坐标系中,其坐标为x,y,两个站之间默认用无线电通话,无线电传播距离有限,所有站会配备一样的无线电,同时,有S个站可以配备卫星,可以传播无限距离,求令所有站都能互相通话(直接或间接)所需无线电传播距离的最小值

时限

2000ms/6000ms

输入

第一行正整数times,其后times组数据,每组数据第一行两个正整数S,P,其后P行,每行两个整数x,y

限制

1<=S<=100;S< P<=500;0<=x,y<=10000

输出

每行一个保留两位小数的浮点数,为所需传播距离最小值

样例输入

1
2 4
0 100
0 300
0 600
150 750

样例输出

212.13

讨论

图论,最小生成树,prim算法,毕竟是完全图,而且肯定用邻接矩阵,先算出两点间距离构造出邻接矩阵,然后prim得到最小生成树每条边的权值,然后排序选择第S大的即可
另外,国家队04年吴景岳的论文中也有这个题,在论文中他给出了较为严谨的证明,额在这里就不班门弄斧了

题解状态

2164K,32MS,C++,1176B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<functional>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 502
#define memset0(a) memset(a,0,sizeof(a))

int S, P;//卫星数 前哨站数
int x[MAXN], y[MAXN];//坐标
double graph[MAXN][MAXN], dis[MAXN];//graph 邻接矩阵 distance 连接树与树外点的最短边权值
bool mk[MAXN];//marked 标记是否已在最小生成树中
double fun()
{
    for (int p = 0; p < P; p++) {
        scanf("%d%d", &x[p], &y[p]);//input
        mk[p] = 0;//顺手清零mk数组
    }
    for (int p = 0; p < P; p++) {
        graph[p][p] = 0.0;
        for (int i = p + 1; i < P; i++)
            graph[p][i] = graph[i][p] = sqrt(double(x[p] - x[i])*(x[p] - x[i]) + (y[p] - y[i])*(y[p] - y[i]));//求出两点间距离初始化邻接矩阵
    }
    mk[0] = 1;//将第一个点加入树
    for (int p = 0; p < P; p++)
        dis[p] = graph[0][p];//初始化最短距离
    for (int p = 1; p < P; p++) {//再运行P-1次
        double least = INF;//最短边权值
        int pos;//最短边连接的点
        for (int i = 0; i < P; i++)
            if (!mk[i] && least>dis[i]) {
                least = dis[i];
                pos = i;
            }//找出连接树与树外点的最短边
        mk[pos] = 1;//加入树
        for (int p = 0; p < P; p++)
            if (!mk[p] && dis[p]>graph[pos][p])
                dis[p] = graph[pos][p];//更新最短距离
    }
    sort(dis, dis + P, greater<double>());//降序排序
    return dis[S - 1];//返回第S大的边权值
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    int times;
    scanf("%d", &times);//input
    while (times--) {
        scanf("%d%d", &S, &P);//input
        printf("%.2lf\n", fun());//output
    }
}

EOF

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值