• AcWing 1125 牛的旅行


    一、理清概念

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

    由于最后连接两个牧场的路线可以在两个连通块间的点枚举添加,目标是直径最小,那么取出添加的最小值。

    但这个最小值未必就是答案,原因是就算你这个最小,但问题是原来连通块中的直径可能还比这个值大,那么根据定义,原来的直径才算是现在连通后真正的直径,还需要\(PK\)一下最大值。太绕了,终于说清楚了...

    二、代码实现

    #include <bits/stdc++.h>
    using namespace std;
    #define x first
    #define y second
    typedef pair<int, int> PII;
    const int N = 152;
    const int INF = 0x3f3f3f3f;
    
    PII q[N];       //每个牧区的坐标
    char g[N][N];   //地图
    double d[N][N]; //每两个牧区之间的距离
    double maxd[N]; //距离牧区i最远的最短距离是多少
    //计算两个牧区之间的距离
    double get_dist(PII a, PII b) {
        int x = a.x - b.x, y = a.y - b.y;
        return sqrt(x * x + y * y);
    }
    
    int main() {
        //牧区小,牧场大
        int n; //牧区数
        cin >> n;
        for (int i = 0; i < n; i++) cin >> q[i].x >> q[i].y; //牧区的坐标
        //一个对称邻接矩阵,图的样子,g是一个二维char数组,一次读入一行
        for (int i = 0; i < n; i++) cin >> g[i];
    
        //遍历行与列,计算出每两个牧区之间的距离
        //距离只在同一连通块中存在,不同的连通块间的距离是INF
        //自己与自己的距离是0
        //如果两个牧区相连,那么距离的计算办法是sqrt((x1-x2)^2+(y1-y2)^2)
        //欧几里得距离
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i == j)
                    d[i][j] = 0;
                else if (g[i][j] == '1')
                    d[i][j] = get_dist(q[i], q[j]);
                else //注意:由于d数组是一个double类型,不能用memset(0x3f)进行初始化正无穷
                    d[i][j] = INF;
            }
        }
        // Floyd算法模板
        for (int k = 0; k < n; k++)
            for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                    d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    
        double res1 = 0; //未建设两个连通块之间线路前,已知的牧区间最大距离是多少
        double res2 = INF;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) //求i到离i(最短距离)最远点的距离
                /*注意一下这个INF/2的用法,很经典,松弛操作后不见的是INF
                只有小于INF/2才是真正被更新的了有效距离*/
                if (d[i][j] < INF / 2) maxd[i] = max(maxd[i], d[i][j]);
            // res1保持原来(两个牧场中)任意两个牧区间的最大距离(直径)
            res1 = max(res1, maxd[i]);
        }
        //连线操作,更新新牧场直径
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (d[i][j] > INF / 2) //如果i,j不在同一个连通块内
                    //连接原来不在同一连通块中的两个点后,可以取得的最小直径
                    res2 = min(res2, maxd[i] + maxd[j] + get_dist(q[i], q[j]));
        // PK一下
        printf("%.6lf\n", max(res1, res2));
        return 0;
    }
    
  • 相关阅读:
    vim does not map customized key?
    再说vundle: 完全vim字符编程的四个必须插件
    centos7 没有iptables服务 file or directory? 用secureCRT登录centos?
    php基础语法-函数等
    windows下vmware10.0 安装centos7
    fedora23的firefox不能播放优酷视频?
    linux如何隐藏和显示所有窗口?
    fedora23忘记root密码怎么办??
    mouse scrollings and zooming operations in linux & windows are opposite
    windows 杂项
  • 原文地址:https://www.cnblogs.com/littlehb/p/16025700.html
Copyright © 2020-2023  润新知