USACO原题,做过几次了,所以一次AC,就是暴搜,因为数据小。
先把每个牧区的直径求出来,然后再把在一个牧区中距离任意节点的最远距离算出来,然后暴搜,若i,j之间加一条路,那么新牧区的半径要么就是i所在的牧区的的直径,要么是j所在的牧区的直径,要么就是i所在的牧区中距i最远的距离加上j所在的牧区中距j最远的距离加上i,j之间的距离。
看代码最有效:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define INF 100000000
struct dot{
int x, y;
}dot[150];
int n;
double dis[150][150];
double dir[150];
int group[150];
double maxdis[150];
char can[150][150];
double getdis(int a, int b)
{
double t;
t = sqrt((double)(dot[a].x - dot[b].x) * (dot[a].x - dot[b].x) +
(dot[a].y - dot[b].y) * (dot[a].y - dot[b].y));
return t;
}
void makegroup(int a, int b)
{
int i;
group[a] = b;
for(i = 0; i < n; i++){
if(can[a][i] && group[i] != b){
makegroup(i, b);
}
}
}
void init(void)
{
int i, j;
scanf("%d\n", &n);
for(i = 0; i < n; i++){
scanf("%d%d\n", &dot[i].x, &dot[i].y);
}
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
scanf("%c", &can[i][j]);
can[i][j] -= '0';
//确实不知道这个i == j, dis = 0可以影响程序的运行
//刚刚仔细查了一下, 原来是在获取dis[i][i]的时候得到了错误的值(非0)
//然后再计算半径的时候就使用了那个错误的较大的值, 导致程序错了.
if(i == j){
dis[i][j] = 0;
}else if(can[i][j] == 0){
dis[i][j] = INF;
}else{
dis[i][j] = getdis(i, j);
}
}
scanf("\n");
}
}
int main(int argc, char **argv)
{
int i, j, k;
double ans = INF, t;
init();
for(i = 0, j = 1; i < n; i++){
if(!group[i]){
makegroup(i, j);
j++;
}
}
for(k = 0; k < n; k++){
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
if(group[i] == group[j] && group[i] == group[k]){
if(dis[i][j] > dis[i][k] + dis[k][j]){
dis[i][j] = dis[i][k] + dis[k][j];
}
}
}
}
}
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
if(group[i] == group[j] && dir[group[i]] < dis[i][j]){
dir[group[i]] = dis[i][j];
}
if(group[i] == group[j] && maxdis[i] < dis[i][j]){
maxdis[i] = dis[i][j];
}
}
}
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
if(group[i] == group[j]){
continue;
}
t = maxdis[i] + maxdis[j] + getdis(i, j);
if(t < dir[group[i]]){
t = dir[group[i]];
}
if(t < dir[group[j]]){
t = dir[group[j]];
}
if(ans > t){
ans = t;
}
}
}
printf("%.6lf", ans);
return 0;
}