题目描述
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; }