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;
}