1 条题解

  • 0
    @ 2025-8-24 21:26:03

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar heidoudou
    **

    搬运于2025-08-24 21:26:02,当前版本为作者最后更新于2018-09-05 12:52:19,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这一题非常之绕。首先需要弄清楚以下几个概念:

    1. 牧区: 对应一个点。
    2. 牧区之间的距离:实际上是两点之间的 最短路。 不要理解成欧几里得距离。只有 直接连接 的时候,才可以计算欧几里得距离。
    3. 牧场: 一个连通块。
    4. 牧场直径: 一个牧场的直径是这个牧场所有的牧区(点)之间 距离 的最大值。 说的绕一点就是 最短路的最大值。
    5. 使用一条边连接两个牧场,使得合成的一个新的牧场的直径最小。意思是加入一条边之后,使得新的牧场的所有点对之间 最短路 的最大值 最小。

    这道题的正解思路是:

    1. 使用 DFS 对连通块染色标记:区分牧场。O(V+E)=O(n2)O(V + E) = O(n^2)
    2. 使用 Floyd-Warshall 算法计算所有点对之间的 最短路O(n3)O(n^3)
    3. 计算每个牧场中,每个牧区点到其他点的 最短路 的最大值。(后面加边的时候要用)
    4. 计算每个牧场中,所有最短路的最大值,即每个牧场的直径。 这个可以与 3 一起计算。 O(n2)O(n^2)
    5. 最后是找答案:对任意两个点,先判断是否同一个牧场。如果不是,考虑加入一条边,变成一个新的牧场。可以直接计算出通过这条边的最短路的最大值。 需要注意的是,通过这条边的最短路的最大值不一定是新牧场的所有最短路的最大值。这里需要比较三个值(牧场 A 的所有最短路的最大值; 牧场 B 的所有最短路的最大值, 加边后通过这条边的最短路的最大值),才能得到正确的新牧场的直径。 遍历所有点对(或者一半), 找出 “新直径” 的最小值。 O(n2)O(n^2)

    最后的时间复杂度是 O(n3)O(n^3)。 空间复杂度也只是 O(n2)O(n^2)

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    struct Point
    {
        int x, y;
        double distance(const Point &b)
        {
            return sqrt((x - b.x) * (x - b.x) + (y - b.y) * (y - b.y));
        }
    };
    
    const int MAX_N = 150;
    const double INF = 1e20;
    int n;
    int field[MAX_N] = {0};
    double diameter[MAX_N + 1] = {0};
    double dist[MAX_N][MAX_N];
    
    void dfs(int i, int id)
    {
        field[i] = id;
        for (int j = 0; j < n; ++j)
            if (!field[j] && dist[i][j] < INF)
                dfs(j, id);
    }
    
    int main()
    {
        int i, j, k;
        Point a[MAX_N];
        scanf("%d\n", &n);
        for (i = 0; i < n; ++i)
            scanf("%d %d\n", &a[i].x, &a[i].y);
        
        char s[MAX_N + 1];
        for (i = 0; i < n; ++i)
        {
            scanf("%s", s);
            for (j = 0; j < n; ++j)
            if (s[j] == '1' || i == j)
                dist[i][j] = a[i].distance(a[j]);
            else
                dist[i][j] = INF;
        }
    
        // 1. DFS
        int id = 0;
        for (i = 0; i < n; ++i)
            if (!field[i])
                dfs(i, ++id);
        
        // 2. Floyd-Warshall
        for (k = 0; k < n; ++k)
            for (i = 0; i < n; ++i)
                for (j = 0; j < n; ++j)
                    if (dist[i][k] + dist[k][j] < dist[i][j])
                        dist[i][j] = dist[i][k] + dist[k][j];
    
        // 3.4. max_sp: find max shortest path and diameter;
        double max_sp[MAX_N];
        for (i = 0; i < n; ++i)
        {
            max_sp[i] = 0.0;
            for (j = 0; j < n; ++j)
                if (dist[i][j] < INF)
                    max_sp[i] = max(max_sp[i], dist[i][j]);
            diameter[field[i]] = max(diameter[field[i]], max_sp[i]);
        }
    
        // 5. find answer
        double min_d = INF, max_d;
        for (i = 0; i < n; ++i)
            for (j = i + 1; j < n; ++j)
                if (field[i] != field[j])
                {
                    max_d = max(max(diameter[field[i]], diameter[field[j]]),
                                max_sp[i] + a[i].distance(a[j]) + max_sp[j]);
                    min_d = min(min_d, max_d);
                }
    
        printf("%.6f\n", min_d);
    
        return 0;
    }
    
    • 1

    信息

    ID
    515
    时间
    1000ms
    内存
    128MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者