洛谷P1522 牛的旅行 Cow Tours
题意:
给定一片牧区,一片所有连通的牧区称为一个牧场。要求在两个不连通的牧场的牧区之间添加一条路径,使得两个牧场连接,并且求得再老牧场和新牧场里面的牧场直径最大值的最小值是多少。
思路:
首先根据题意我们得知我们需要求得每个牧场的直径的大小,即牧场里面的牧区之间的最短路径的最大值;其次,我们需要在不联通的牧场之间添加一条路径使得两个牧场连接。
所以我们需要求得每两个牧区之间的最短路径,也就是多源汇最短路,即Floyd算法。
①:使用Floyd算法求得任意两个牧区之间的最短路。
②:求得每个牧场的直径,即从当前牧区开始能联通的牧区的最短路的最大值储存在maxd[i]中。
③:求得加上路径之后的牧场的最大直径的最小值。由于是新老牧场,所以我们要分两种情况:1、老牧场的直径的最大值;2、加上路径之后的直径的最小值。
代码:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cmath> #define x first #define y second using namespace std; typedef pair<int, int> PII; typedef long long LL; const int N = 160; const double INF = 1e20; int n, m; PII s[N]; char g[N][N]; double dist[N][N]; double maxd[N]; double get(PII a, PII b) { int dx = a.x - b.x; int dy = a.y - b.y; return sqrt((LL)dx * dx + (LL)dy * dy); } int main() { scanf("%d", &n); for (int i = 1; i <= n; i ++ ) { int x, y; scanf("%d%d", &x, &y); s[i] = {x, y}; } for (int i = 1; i <= n; i ++ ) scanf("%s", g[i] + 1); for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) if (i != j) dist[i][j] = INF; for (int i = 1; i <= n; i ++ ) for (int j = i + 1; j <= n; j ++ ) if (g[i][j] == '1') dist[i][j] = dist[j][i] = get(s[i], s[j]); for (int k = 1; k <= n; k ++ ) for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) if (dist[i][j] < INF) maxd[i] = max(maxd[i], dist[i][j]); // 老牧场的直径 double res1 = 0; for (int i = 1; i <= n; i ++ ) res1 = max(res1, maxd[i]); // 老牧场直径的最大值 double res2 = INF; for (int i = 1; i <= n; i ++ ) for (int j = i + 1; j <= n; j ++ ) if (dist[i][j] >= INF) res2 = min(res2, maxd[i] + maxd[j] + get(s[i], s[j])); // 加上一条路径之后的直径的最小值,因为求最大值得话可能存在一条比老牧区的直径大但是比当前的最小值更小的值 printf("%lf\n", max(res1, res2)); return 0; }