[POJ 2349] Arctic Network Kruskal

题目传送门:【POJ 2349】

题目大意:国防部(DND)要用无线网络连接北部几个哨所。两种不同的通信技术被用于建立网络:每一个哨所有一个无线电收发器,一些哨所将有一个卫星频道。
任何两个有卫星信道的哨所可以通过卫星进行通信,而不管他们的位置。同时,当两个哨所之间的距离不超过 D 时可以通过无线电通讯,D 取决于对收发器的功率。功率越大,D 也越大,但成本更高。出于采购和维修的方便,所有哨所的收发器必须是相同的;那就是说,D 值对每一个哨所相同。

你的任务是确定收发器的 D 的最小值。每对哨所间至少要有一条通信线路(直接或间接)。

题目分析:
一道略考思维的 Kruskal 题目。

由于我们在最开始的时候不知道哪些哨所拥有卫星通信设备,所以为了求出最后的答案,我们先要将所有的哨所之间的距离求出来(相当于构造一个完全图)。
之后,我们可以根据题意,用 Kruskal 求出它的最大边权值作为收发器的 D 值。
但是本题有一个特点:能够进行卫星通讯的两点不用考虑它的边权!
所以,在这个算法中,原本被选中的最后 S 条边就可以忽略不计。

例如:P = 5 , 5 个哨所的坐标分别为 (0 , 125) , (100 , 0) , (300 , 0) , (100 , 250) , (200 , 200) 。每条边的权值从小到大排序为 {111.80 , 160.08 , 160.08 , 200 , 213.60 , 223.61 , 223.61 , 250 , 320.16 , 325};
当 S = 0 时,按照 Kruskal 的方法,此时得到的最大边权为 200;但当 S = 3 时,结果变为了第 (5 - 3) = 2 条边的边权 (160.08) 。

下面附上代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MX = 1005;

struct Edge{
    int u,v;
    double len;
};
Edge edge[MX*MX];
int s,p,te = 0,cnt = 0;                             //te:总边数 
int locat[MX][2],fa[MX];
double map[MX][MX],res[MX];

bool comp(const Edge& i,const Edge &j){
    return i.len < j.len;
}
double cdis(int a1,int a2,int b1,int b2){           //得到两个点之间的距离 
    double x = ((b1-a1) * (b1-a1) + (b2-a2)*(b2-a2));
    return sqrt(x);
}
int find(int x){return fa[x] == x ? x : fa[x] = find(fa[x]);}
void kruskal(){
    int k = 0;
    for (int i = 1;i <= p;i++) fa[i] = i;
    sort(edge + 1,edge + te + 1,comp);
    for (int i = 1;i <= te;i++){
        int x = find(edge[i].u), y = find(edge[i].v);
        if (k >= p-1) break;
        if (x != y){
            res[cnt++] = edge[i].len;
            k++;
            fa[x] = y;
        }
    }
}
int main(){
    int T;
    cin>>T;
    while (T--){
        memset(locat,0,sizeof(locat));
        memset(map,0,sizeof(map));
        memset(edge,0,sizeof(edge));
        te = 0, cnt = 0;
        cin>>s>>p;
        for (int i = 1;i <= p;i++){
            cin>>locat[i][0]>>locat[i][1];
        }
        for (int i = 1;i <= p;i++){
            for (int j = 1;j <= p;j++){
                map[i][j] = cdis(locat[i][0],locat[i][1],locat[j][0],locat[j][1]);
                if (i <= j){
                    edge[++te].u = i;
                    edge[te].v = j;
                    edge[te].len = map[i][j];
                }
            }
        }
        kruskal();
        printf("%.2lf\n",res[cnt - s]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值