这道题,很无语。感觉就是卫星代替s-1条边。
以下大号字摘自IOI2004国家集训队论文《最小生成树算法及其应用》(吴景岳):
当正向思考受阻时, 逆向思维可能有奇效。 本题就是这样。 知道卫星设备的数量,求最小的收发距离,可能比较困难;如果知道距离求数量,就很简单了。把所有可以互相通讯的村庄连接起来, 构成一个图。 卫星设备的台数就是图的连通支的个数。
问题转化为:找到一个最小的 d,使得把所有权值大于 d 的边去掉之后,连通支的个数小于等于 k。
先看一个定理。 定理 2: 如果去掉所有权值大于 d 的边后, 最小生成树被分割成为 k 个连通支,图也被分割成为 k 个连通支。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
class Node
{
public:
double x,y;
}dir[550];
double gragh[1100][1100];
double record[550];
double dis[550];
int visit[550];
int s,p,l;
bool cmp(double a,double b)
{
return a>b;
}
double distance(double x1,double y1,double x2,double y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void prim()
{
l = 0;
memset(visit,0,sizeof(visit));
for(int i = 1;i <= p; i++)
dis[i] = gragh[1][i];
visit[1] = 1;
int pos;
for(int i = 1;i < p; i++){
double Min = 999999999;
for(int j = 1;j <= p; j++){
if(visit[j] == 0 && Min > dis[j]){
Min = dis[j];
pos = j;
}
}
visit[pos] = 1;
record[l++] = Min;
for(int j = 1;j <= p; j++){
if(visit[j] == 0 && gragh[pos][j] < dis[j]){
dis[j] = gragh[pos][j];
}
}
}
}
int main()
{
// freopen("in.txt","r",stdin);
int n;
scanf("%d",&n);
while(n--){
scanf("%d%d",&s,&p);
for(int i = 1;i <= p; i++)
scanf("%lf%lf",&dir[i].x,&dir[i].y);
for(int i = 1;i <= p; i++){
for(int j = 1;j <= p; j++){
gragh[i][j] = distance(dir[i].x,dir[i].y,dir[j].x,dir[j].y);
}
}
prim();
sort(record,record+l,cmp);
printf("%.2f\n",record[0]);
}
return 0;
}