• PAT甲级1003Emergency


    题目链接

    https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376

    题解

    题目要求

    • 有几个城市,每个城市中有多个救援队,城市间由公路相连,公路的长度不一

    • 输入

      • N:正整数,不超过500,城市的数量,城市索引为[0,N-1]

      • M:公路的数量

      • c1:你现在所在的城市

      • c2:你需要去的城市

      • 各城市中救援队数量:N个整数

      • 各条公路连接的两个城市其该公路的长度:M行

        保证c1到c2至少有一条路径

    • 输出

      • c1到c2的最短路径的数量
      • 在保证路径最短的前提下,最多可以聚集多少只救援队

    解题思路

    • dijkstra算法

      • 特点

        • 适用于边权为正的情况
        • 单源最短路(Single-Source Shortest Paths,SSSP),求单个源点到所有结点的最短路
        • 同时适用于有向图和无向图
      • 伪代码

        n个结点

        bool visited[n];  // 标记:是否找到源点s到某点的最短路径
        int dis[n]; // 记录源点s到某点的最短路径的长度
        int w[n][n]; // 结点间的距离
        
        visited数组置false;
        dis数组置无穷大,dis[s]置0;
        循环n次{
            寻找未被标记的、距离结点s最近的结点u;
            如果找到u则将其标记(visited[u] = true),否则结束循环;
            如果存在边<u,v>,则更新dis[v] = min(dis[v], dis[u] + w[u][v]); // 贪心
        }
        
    • 其它

      • c1到c2的最短路径的数量pathNum

        • 如果dis[v] < dis[u] + w[u][v],则pathNum[v] = path[u]

          u到v只有一条边,所以源点到u和v的路径的数量相等

        • 如果dis[v] == dis[u] + w[u][v],则pathNum[v] = path[u] + path[v]

          在距离相等的情况下,除了经过u,还可以从其他结点到达v

      • 在保证路径最短的前提下,最多可以聚集多少只救援队

        • 如果dis[v] < dis[u] + w[u][v],则teamGatherNum[v] = teamGatherNum[u] + teamNum[v]

        • 如果dis[v] == dis[u] + w[u][v],则teamGatherNum[v] = min(teamGatherNum[v], teamGatherNum[u] + teamNum[v])

          此时最短路径不止一条,所以要判断哪条路径聚集的救援队更多

    代码

    // Problem: PAT Advanced 1003
    // URL: https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376
    // Tags: 最短路 djikstra DFS 单源最短路 贪心
    
    #include <iostream>
    #include <climits>
    using namespace std;
    
    const int MAXN =  500; // 最多500个城市
    const int INF = INT_MAX; // 最大距离
    int cityDis[MAXN][MAXN]; // 城市间的距离
    int teamNum[MAXN]; // 每个城市中有多少个救援队
    int shortestPathDis[MAXN]; // 起点城市c1到各个城市最短路径的距离
    int shortestPathNum[MAXN]; // 起点城市c1到各个城市最短路径的数量
    int teamGatherNum[MAXN]; // 从起点城市c1到各个城市的最短路径上,最多能聚集到多少个救援队
    bool visited[MAXN];  // 标记:是否已求出起点城市c1到某城市的最短路径
    
    int main()
    {
        // 初始化变量
        fill(cityDis[0], cityDis[0] + MAXN * MAXN, INF);
        fill(shortestPathDis, shortestPathDis + MAXN, INF);
    
        // 读取输入
        int n, m, c1, c2;
        scanf("%d %d %d %d", &n, &m, &c1, &c2);
        for (int i = 0; i < n; i++)
            scanf("%d", &teamNum[i]);
        int a, b, d;
        for (int i = 0; i < m; i++){
            scanf("%d %d %d", &a, &b, &d);
            cityDis[a][b] = cityDis[b][a] = d;
        }
    
        // 初始化起点城市c1
        shortestPathDis[c1] = 0;
        teamGatherNum[c1] = teamNum[c1];
        shortestPathNum[c1] = 1;
    
        // 迭代直至求出起点城市c1到所有城市的最短距离
        for (int i = 0; i < n; i++){
            // 寻找未被标记的、距离起点城市c1最近的城市u(贪心)
            int u = -1, minDis = INF;
            for(int j = 0; j < n; j++){
                if (!visited[j] && shortestPathDis[j] < minDis){
                    u = j;
                    minDis = shortestPathDis[j];
                }
            }
            // 各城市都已被标记,则已求出结果,退出循环即可;否则根据贪心策略,现在已求出起点城市c1到城市u的最短距离
            if (u == -1)
                break;
            visited[u] = true;
            // 如果有边<u,v>,则更新城市v的相关变量(最简洁的dijkstra算法只更新shortestPathDis[v]即可)
            for (int v = 0; v < n; v++){
                if (!visited[v] && cityDis[u][v] != INF){
                    if (shortestPathDis[v] > shortestPathDis[u] + cityDis[u][v]){
                        shortestPathDis[v] = shortestPathDis[u] + cityDis[u][v];
                        shortestPathNum[v] = shortestPathNum[u];
                        teamGatherNum[v] = teamGatherNum[u] + teamNum[v];
                    }
                    else if (shortestPathDis[v] == shortestPathDis[u] + cityDis[u][v]){
                        shortestPathNum[v] = shortestPathNum[u] + shortestPathNum[v];
                        if (teamGatherNum[v] < teamGatherNum[u] + teamNum[v])
                            teamGatherNum[v] = teamGatherNum[u] + teamNum[v];
                    }
                }
            }
        }
        printf("%d %d", shortestPathNum[c2], teamGatherNum[c2]);
        return 0;
    }
    

    参考链接

    https://blog.csdn.net/liuchuo/article/details/52300668

    https://blog.csdn.net/qq_35644234/article/details/60870719


    作者:@臭咸鱼

    转载请注明出处:https://www.cnblogs.com/chouxianyu/

    欢迎讨论和交流!


  • 相关阅读:
    Centos5.8 安装 ImageMagick 6.8.9-3
    Centos5.8 安装 Redmine
    Apache配置中的ProxyPass 和 ProxyPassReverse
    Centos5.8 安装SVN并配置HTTP访问
    Centos5.8 安装 MySQL5.6.19
    Centos5.8 安装 PHP5.5 和 memcached
    CentOS RHEL 安装 Tomcat 7
    Centos5.8 iptables管理
    在SecureCRT中使用rz和sz传输文件
    在Mac mini上安装 ESXi 5.5
  • 原文地址:https://www.cnblogs.com/chouxianyu/p/13686461.html
Copyright © 2020-2023  润新知