2013资格赛——桃花群岛

本文介绍了一种使用最小生成树算法解决岛屿间通讯覆盖问题的方法。通过Prim算法找到最小生成树,并确定其最长边作为通讯器的最大半径,从而实现所有岛屿的有效通讯连接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

李四kmp实际上才是黄药师的嫡系大弟子,他继承了黄药师的所有地产---桃花群岛。桃花群岛包含n个小岛(2<=n<=500)。李四kmp想在n个岛上建个通讯系统保证小岛可以直接或间接通讯。他想在每个岛上装上规格相同的无线电通讯器,每个无线电通讯器的通讯范围为半径r的圆形。如果不同的小岛通讯范围相交或相切那么这两个小岛可以相互通讯(李四kmp的无线通讯器确实很高科技)。通讯器的通讯范围半径r越小,价格越便宜,为了保证n个小岛能相互通讯,且花费最小。李四kmp该买的通讯器的半径r该是多少?

Input

输入包含多组数据。每组数据先输入一个n,接着是n个小岛的平面坐标x,y(-10000 <= x,y <= 10000).

Output

对每组输入,先输出一行”Case T:”,T初始为1。每组输出相应的r,保留两位小数。

Sample Input

2
0 0
0 1
3
0 0
2 2
5 5

Sample Output

Case 1:
0.50
Case 2:
2.12


分析:一开始这题不会,后来问了一下。其实,本题就是求最小生成树中的最长边,此最长边即为其直径,然后即可求得半径。用Prim算法求出最小生成树。

归根结底就是证明这个“最小生成树的最长边小于等于其它任意生成树的最长边”。简易的证明如下:

1.先证最小生成树T的最长边(u,v)小于等于任一生成树T的最长边
反证:假设不满足上述命题,即:存在一个生成树T',其最长边小于(u,v)
则有T'的任一边 <= T’最长边 < (u,v),
因为T'是生成树,则其上u,v两点间必存在唯一通路P;
由于u,v位于(u,v)所通过的某割的两边,P上必有一边(x,y)通过割且(x,y)<(u,v)
在T上去掉(u,v)加上(x,y)形成T''可证T‘’仍然是生成树且所有边权值和小于T的权值和。与T是最小生成树矛盾。得证
2.再证存在一个可达的方案,其最长边等于(u,v),即1中的下限是紧确的。
 显然,只要选取最小生成树为所选方案即可得
click it : http://poj.org/showmessage?message_id=340459

然后代码就不难了,只要会Prim算法即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>

const int maxn = 505;
double g[maxn][maxn];
double x[maxn],y[maxn];
double flag;
int n;
bool vis[maxn];
double dis[maxn];

int main() {
    int cas = 1;
    while(~scanf("%d" , &n)) 
    {
        for(int i=0;i<n;i++) 
            scanf("%lf%lf",&x[i],&y[i]);
        for(int i=0;i<n;i++) 
        {
            g[i][i] = 0;
            for(int j=i+1;j<n;j++) 
            {
                g[i][j] = g[j][i] = sqrt( (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]) );
            }
        }
        flag = 0;
        for(int i=0;i<n;i++) 
        {
            vis[i] = false;
            dis[i] = 1000000000;
        }
        dis[0] = 0;
        while(1) 
        {
            int u = -1 , tmp = 100000000;
            for(int i=0;i<n;i++)
            {
                if(!vis[i] && dis[i] < tmp) {
                    u = i;
                    tmp = dis[i];
                }
            }
            if(dis[u] > flag) flag = dis[u];
            if(u == -1) break;
            vis[u] = true;
            for(int i=0;i<n;i++) 
            {
                if(!vis[i] && g[u][i] < dis[i])
                {
                    dis[i] = g[u][i];
                }
            }
        }
        printf("Case %d:\n" , cas++);
        printf("%.2lf\n" , flag/2.0);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值