题目描述
Farmer John 的农场里有很多牧区。有的路径连接一些特定的牧区。一片所有连通的牧区称为一个牧场。但是就目前而言,你能看到至少有两个牧区通过任何路径都不连通。这样,Farmer John 就有多个牧场了。
John 想在牧场里添加恰好一条路径。对这条路径有以下限制:
一个牧场的直径就是牧场中最远的两个牧区的距离(本题中所提到的所有距离指的都是最短的距离)。考虑如下的有5个牧区的牧场,牧区用 * 表示,路径用直线表示。每一个牧区都有自己的坐标:
(15,15) (20,15)
D E
*-------*
| _/|
| _/ |
| _/ |
|/ |
*--------*-------*
A B C
(10,10) (15,10) (20,10)
这个牧场的直径大约是 12.0710612.0710612.07106,最远的两个牧区是 A 和 E,它们之间的最短路径是 A→B→EA \to B \to EA→B→E。
这里是另一个牧场:
*F(30,15)
/
_/
_/
/
*------*
G H
(25,10) (30,10)
在目前的情景中,他刚好有两个牧场。John 将会在两个牧场中各选一个牧区,然后用一条路径连起来,使得连通后这个新的更大的牧场有最小的直径。
注意,如果两条路径中途相交,我们不认为它们是连通的。只有两条路径在同一个牧区相交,我们才认为它们是连通的。
输入文件包括牧区、它们各自的坐标,还有一个如下的对称邻接矩阵:
:
A B C D E F G H
A 0 1 0 0 0 0 0 0
B 1 0 1 1 1 0 0 0
C 0 1 0 0 1 0 0 0
D 0 1 0 0 1 0 0 0
E 0 1 1 1 0 0 0 0
F 0 0 0 0 0 0 1 0
G 0 0 0 0 0 1 0 1
H 0 0 0 0 0 0 1 0
其他邻接表中可能直接使用行列而不使用字母来表示每一个牧区。输入数据中不包括牧区的名字。
输入文件至少包括两个不连通的牧区。
请编程找出一条连接两个不同牧场的路径,使得连上这条路径后,这个更大的新牧场有最小的直径。输出在所有牧场中最小的可能的直径。
输入格式
第一行一个整数 NNN(1≤N≤1501 \leq N \leq 1501≤N≤150),表示牧区数。
接下来 NNN 行,每行两个整数 X,YX,YX,Y(0≤X,Y≤1050 \leq X ,Y \leq 10^50≤X,Y≤105),表示 NNN 个牧区的坐标。注意每个牧区的坐标都是不一样的。
接下来 NNN 行,每行 NNN 个数字,代表邻接矩阵。
输出格式
只有一行,包括一个实数,表示所求直径。数字保留六位小数。
只需要打到小数点后六位即可,不要做任何特别的四舍五入处理。
输入输出样例
输入 #1
8
10 10
15 10
20 10
15 15
20 15
30 15
25 10
30 10
01000000
10111000
01001000
01001000
01110000
00000010
00000101
00000010
输出 #1
22.071068
说明/提示
翻译来自NOCOW
USACO 2.4
找出每个点与其连通点的最远距离,然后枚举不连通的点。
#include <iostream>
#include <algorithm>
#include <climits>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
const int inf = 1e9 + 100;
const int maxn = 230;
double a[maxn][maxn];
struct node{
int x, y;
}point[maxn];
int n;
double d[maxn];
double getDis(node x, node y) {
return sqrt(pow(x.x - y.x, 2) + pow(x.y - y.y, 2));
}
int main() {
cin >> n;
fill(a[0], a[0] + maxn * maxn, inf);
for(int i = 1; i <= n; i++)
cin >> point[i].x >> point[i].y;
string str;
for(int i = 1; i <= n; i++) a[i][i] = 0;
for(int i = 1; i <= n; i++) {
cin >> str;
for(int j = 0; j < str.size(); j++) {
if(str[j] == '1') {
double dis = getDis(point[i], point[j + 1]);
a[i][j + 1] = a[j + 1][i] = dis;
}
}
}
for(int k= 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
a[i][j] = min(a[i][j], a[i][k] + a[k][j]);
double ans1 = 0, ans2 = inf;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(a[i][j] != inf)
d[i] = max(d[i], a[i][j]), ans1 = max(ans1, d[i]);
}
}
for(int i = 1; i <= n; i++) {
for(int j = i + 1; j <= n; j++) {
if(a[i][j] == inf)
ans2 = min(ans2, getDis(point[i], point[j]) + d[i] + d[j]);
}
}
printf("%.6lf", max(ans1, ans2));
return 0;
}