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, C1 and C2 - 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 c1, c2 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 C1 to C2.
Output Specification:
For each test case, print in one line two numbers: the number of different shortest paths between C1 and C2, 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]即为本地答案