PAT 1003 Emergency (Dijkstra算法 ) 示例解析

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:

Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C​1​​ and C​2​​ - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c​1​​, c​2​​ and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C​1​​ to C​2​​.

Output Specification:

For each test case, print in one line two numbers: the number of different shortest paths between C​1​​ and C​2​​, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:

5 6 0 2 
1 2 1 5 3
0 1 1 
0 2 2 
0 3 1 
1 2 1 
2 4 1 
3 4 1 

Sample Output:

2 4

题目含义:输入城市数目n个,城市道路m条,每个城市有自己的救援小组,所有的路的权重已知。给定起点和终点,求出起点到重点的最短路径数目以及最短路径上的救援小组数目之和。

测试网址:https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376

分析:使用Dijkstra算法

救援小组个数相当于点权,用Dijkstra求出边全最小的最短路径的条数,以及这些最短路径中最大点权值。dis[i] 表示从出发点到i节点最短路径的路径长度,roads[i] 表示从出发点到i节点最短路径的条数,teams[i] 表示从出发点到i点救援队的数目之和,e[u][v] 表示u城市到v城市的路径权重

伪代码:
if dis[u] + e[u][v] < dis[v] 
    dis[v] = dis[u] + e[u][v];
    roads[v] = roads[u];
    teams[v] = teams[u] + weight[v]; 
else if dis[u] + e[u][v] == dis[v]
    roads[v] += roads[u];
    if teams[u] + weight[v] > teams[v]
         teams[v] = teams[u] + weight[v];

实际代码:

#include <iostream>
#include <vector>
#include <limits.h>

using namespace std;

int main() {  
    //读取第一行数据
    int n, m, C1, C2;
    cin>>n>>m>>C1>>C2;
    vector<int> weight(n, 0);
    for (int i = 0; i < n; i++) {
        cin>>weight[i];
    }
    
    vector<vector<int> > edge(n, vector<int>(n, INT_MAX));
    vector<int> dis(n, INT_MAX);
    vector<int> roads(n, 0);
    vector<int> teams(n, 0);
    vector<bool> visit(n, false);

    //初始化边权值表
    int c1, c2, L;
    for (int i = 0; i < m; i++) {
        cin>>c1>>c2>>L;
        edge[c1][c2] = edge[c2][c1] = L;
    }
    dis[C1] = 0;
    teams[C1] = weight[C1];
    roads[C1] = 1;
  
    for (int i = 0; i < n; ++i) {
        int u = -1, minn = INT_MAX;
        for (int j = 0; j < n; j++) {
            if (visit[j] == false && dis[j] < minn) {
                u = j;
                minn = dis[j];
            }
        }
        if (u == -1) break;
        visit[u] = true;
        for (int v = 0; v < n; v++) {
            if (visit[v] == false && edge[u][v] != INT_MAX) {
                if (dis[u] + edge[u][v] < dis[v]) {
                    dis[v] = dis[u] + edge[u][v];
                    roads[v] = roads[u];
                    teams[v] = teams[u] + weight[v];
                } else if (dis[u] + edge[u][v] == dis[v]) {
                    roads[v] = roads[v] + roads[u];
                    if (teams[u] + weight[v] > teams[v]) {
                        teams[v] = teams[u] + weight[v];
                    }
                }
            }
        }
    }
    cout<<roads[C2]<<" "<<teams[C2]<<endl;
    return 0;
}

示例解析:

输入参数

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

转化为图为

这个时候:城市数目n=5,道路条数m=6,起点城市c1=0,终点城市c2 = 2,初始化edge边权矩阵,每个城市的救援队数目weight,

第一步,从起点城市C1出发,即设置dis[C1] = 0,roads[C1] = 1, 这里的dis表示起点城市到城市i的最短距离,visit数组表示该城市是否被访问过,查找距离起点最近的城市,这个城市我们设置为u, 可以看到我们第一次找到的城市必然是C1本身,因为dis[C1]为0,这个时候把visit[C1]设置为true表示访问过,接着去刷新u到其他城市的最短距离,更新dis,roads,teams,更新完之后的结果如下所示,具体过程如下所示

已知u = 0,v = 1, dis[v] = inf,即 dis[u] + edge[u][v] < dis[v]
那么,最短距离变小 dis[v] = dis[u] + edge[u][v],
最短路的条数不变 roads[v] = roads[u],救援数目增加

同理,当v = 2,3,4时依次更新,结果如下图所示

第二步,继续往下走,根据上次产生的dis找到下一个未访问的且距离起点最近的城市,这个时候找到的是城市1,更新一遍后的结果如下所示:

已知u = 1,vist[1] = true, v = 2时,
dis[u] + edge[u][v] = 2 与 dis[v]相等,
此时,路径数目增加,以为可以经过u城市到达城市2,也可以直接到达城市2,相当于路数增加,
roads[v] += roads[u],同样救援队最大数目增加,teams[v] = teams[u] + weight[u];

当 v = 3时,不满足条件,因为 dis[u] + edge[u][v] = 1 + inf > dis[v]
当 v = 4时,同样不满足条件

第三步,找下一个未访问的距离最近的城市是3,u为3的情况下继续更新

u = 3, v = 2, 此时 dis[u] + edge[u][v] = 1 + inf,不满足更新条件
v = 4,此时 dis[u] + edge[u][v] = 1 + 1 < dis[v] = inf, 
此时更新dis[v] = dis[u] + edge[u][v], roads[v] = roads[u], 
teams[v] = teams[u] + weight[v]

第四步,找到下一个未访问的距离最近城市为2,这个时候将vist[u]置为true

已知 u = 2,v = 4,dis[u] + edge[u][v] = 2 + 1 > dis[4] 不满足条件

第五步,找到下一个未访问的距离最近的城市为4,此时其他城市均已访问过,同样没有数据更新操作

最后我们来梳理下,roads为起点到各个城市的最小路径条数,teams为最小路径条件下,起点到各个城市的最大资源数目,那么roads[C2],teams[C2]即为本地答案

参考:https://www.liuchuo.net/archives/2359

我的知乎链接:https://zhuanlan.zhihu.com/c_1241805099740815360

Vivado2023是一款集成开发环境软件,用于设计和验证FPGA(现场可编程门阵列)和可编程逻辑器件。对于使用Vivado2023的用户来说,license是必不可少的。 Vivado2023的license是一种许可证,用于授权用户合法使用该软件。许可证分为多种类型,包括评估许可证、开发许可证和节点许可证等。每种许可证都有不同的使用条件和功能。 评估许可证是免费提供的,让用户可以在一段时间内试用Vivado2023的全部功能。用户可以使用这个许可证来了解软件的性能和特点,对于初学者和小规模项目来说是一个很好的选择。但是,使用评估许可证的用户在使用期限过后需要购买正式的许可证才能继续使用软件。 开发许可证是付费的,可以永久使用Vivado2023的全部功能。这种许可证适用于需要长期使用Vivado2023进行开发的用户,通常是专业的FPGA设计师或工程师。购买开发许可证可以享受Vivado2023的技术支持和更新服务,确保软件始终保持最新的版本和功能。 节点许可证是用于多设备或分布式设计的许可证,可以在多个计算机上安装Vivado2023,并共享使用。节点许可证适用于大规模项目或需要多个处理节点进行设计的用户,可以提高工作效率和资源利用率。 总之,Vivado2023 license是用户在使用Vivado2023时必须考虑的问题。用户可以根据自己的需求选择合适的许可证类型,以便获取最佳的软件使用体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coder567

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值