题目很简单,直接用krusakl算法即可,然后找出第S大的数,S即为卫星的个数。开始的时候我将卫星之间可以直接通信这一条给忽略了,wrong了N久。后来才注意到这一点。如果最小距离D已知的话,把所有铺设线路的村庄链接起来,构成图后,需要卫星设备的数目就是图的连通支的个数。由这一点出发,我们可以考虑在每个连通支中放置一个卫星,同时使得卫星与卫星之间的距离是最大的,这样就保证了D的值最小,显然我们将生成树中最长的S-1条边去掉之后会形成S个连通分支,这样就得到答案,及求解第S最长边。有关的证明,这里就不在写了,证明得考虑两个问题,1是为什么D不可能比第S长边小,2.生成树有多个的情况下如何保证第S长边是相同的。第二点利用的是最小生成树的边经排序,得到的序列是相同的。程序如下:
/*
ID: csuchenan
PROG: uva10369 - Arctic Network
LANG: C++
*/
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
using namespace std ;
struct Point
{
int x ;
int y ;
}point[505] ;
struct Edge
{
int x ;
int y ;
double dist ;
}edge[130000] , key[505] ;
int parent[505] ;
double dist_point(Point x , Point y)
{
return sqrt((double) ( (x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y) )) ;
}
int cmp(const void * a ,const void * b)
{
return (*(Edge *)a).dist > (* (Edge *)b).dist ;
}
void init() ;
int find_x(int x) ;
void join(int x , int y) ;
double kruskal() ;
int n ;
int num ;
int sal ;
int nnum ;
int nlen ;
int main()
{
scanf("%d" , &n) ;
while(n--)
{
scanf("%d %d" , &sal , &num) ;
int i ;
for(i = 0 ; i < num ; i ++)
scanf("%d %d" , &point[i].x , &point[i].y) ;
nnum = 0 ;
int j ;
for(i = 0 ; i < num ; i ++)
{
for(j = i + 1 ; j < num ; j ++)
{
edge[nnum].x = i ;
edge[nnum].y = j ;
edge[nnum].dist = dist_point(point[i] , point[j]) ;
nnum ++ ;
}
}
printf("%.2f\n" , kruskal()) ;
}
return 0 ;
}
void init()
{
int i ;
for(i = 0 ; i < num ; i ++)
{
parent[i] = i ;
}
}
int find_x(int x)
{
int r = x ;
while(parent[r] != r)
r = parent[r] ;
int i ;
int j ;
for(i = x ; parent[i] != r ;)
{
j = parent[i] ;
parent[i] = r ;
i = j ;
}
return r ;
}
void join(int x , int y)
{
int p ;
int q ;
p = find_x(x) ;
q = find_x(y) ;
if(p < q)
parent[q] = p ;
else
parent[p] = q ;
}
double kruskal()
{
init() ;
qsort(edge , nnum , sizeof(edge[0]) , cmp) ;
int i;
nlen = 0 ;
for(i = 0 ; i < nnum ; i ++)
{
if(find_x(edge[i].x) != find_x( edge[i].y))
{
join(edge[i].x , edge[i].y) ;
key[nlen] = edge[i] ;
nlen ++ ;
}
}
return key[nlen - sal].dist ;
}