P1522 [USACO2.4] 牛的旅行 Cow Tours

发布时间 2023-10-01 20:35:49作者: yhx0322

Problem

题目简述

给你两个独立的联通块,求:在两个联通块上各找一个点连起来,使得新的联通块的直径的最小值

思路

本题主要做法:\(Floyd\)

  • 首先,Floyd求出任意两个点之间的最短路。
  • 枚举每一个点,求出以这个点能走到的所有点中距离的最大值。(一定在能走到的情况下,不然默认距离就是0x3f, 会导致结果错误 )
  • \(ma1\) 为最大的直径(每个 \(ma[i]\) 的最大值)。
  • 再设 \(mi1\) 为任意两点加边的新直径的最小值
  • 答案为:\(max(ma1, mi1)\)

代码

#include <iostream>

#define ll long long

using namespace std;


const int N = 160, INF = 0x3f3f3f3f;
double d[N][N], ma1, mi1, ma[N];
ll p[N][3];

ll pf(int x) { return 1LL * x * x; }

double get(int t1, int t2) {
    return sqrt(pf(p[t1][1] - p[t2][1]) + pf(p[t1][2] - p[t2][2]));
}

int n;
char c;

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> p[i][1] >> p[i][2];
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> c;
            if (i == j) d[i][j] = 0;
            else if (c == '1') d[i][j] = get(i, j);
            else d[i][j] = INF;
        }
    }
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (d[i][j] != INF) ma[i] = max(ma[i], d[i][j]);
        }
        ma1 = max(ma1, ma[i]);
    }
    mi1 = INF;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (d[i][j] == INF) mi1 = min(mi1, ma[i] + ma[j] + get(i, j));
        }
    }
    printf("%.6lf", max(ma1, mi1));
    return 0;
}