PAT-A 1003 Emergency (25)

  图的 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.

Problem: PAT-A 1003 Emergency

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

1
2
3
4
5
6
7
8
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

1
2 4

Analysis

  单源最短路径问题,用 Dijkstra 算法。根据题意,每个城市的救援队数量为点权,城市之间的距离为边权。由于题目要求输出结果为最短路径数和最大点权和,添加 num 数组记录起点至各顶点的最短路径数,添加 w 数组记录起点至各个顶点的最大点权和,在计算 d 的同时更新上述两个数组,详情见代码注释。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <bits/stdc++.h>
using namespace std;
const int mxN = 505;

// N:顶点数, M:边数, C1:起点, C2:终点
int N, M, C1, C2;
// G:邻接矩阵, d:起点至各点的最短距离, weight:点权, w:最大点权和, num:最短路径条数
int G[mxN][mxN], d[mxN], weight[mxN], w[mxN], num[mxN];
bool vis[mxN] = {false};

void dijkstra(int s) { // s 为起点

fill(d, d + N, INT_MAX); // 初始化 d 数组
d[s] = 0; // 起点到自身距离为 0
w[s] = weight[s]; // 起点最大点权
num[s] = 1; // 起点至起点路径数为 1

for (int i = 0; i < N; i++) {
int u = -1, MIN = INT_MAX;

// 遍历 N 个点, 寻找最小 d[]和对应顶点
for (int j = 0; j < N; j++) {
if (!vis[j] && d[j] < MIN) {
MIN = d[j];
u = j;
}
}
if (u == -1) return; // 未找到通路,剩下的顶点与起点不通
vis[u] = true; // 标记 u 已访问
for (int v = 0; v < N; v++) {

// 如果 v 未访问, 且 u - v 连通
if (!vis[v] && G[u][v] != INT_MAX) {

// 如果以 u 为中介点至 v 的距离小于已知 d[v]
if (d[u] + G[u][v] < d[v]) {
d[v] = d[u] + G[u][v]; // 更新 d[v]
w[v] = w[u] + weight[v]; // 更新点权和
num[v] = num[u]; // 更新路径数
} else if (d[u] + G[u][v] == d[v]) { // 路径长度相同
w[v] = max(w[v], w[u] + weight[v]); // 比较获取最大点权
num[v] += num[u]; // 路径数累加
}
}
}
}
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> N >> M >> C1 >> C2;

// 读入点权, 即每个城市的救援队数量
for (int i = 0; i < N; i++) {
cin >> weight[i];
}

// 初始化图 G, 边权为无穷大
fill(G[0], G[0] + mxN * mxN, INT_MAX);

// 读入边权, 即每两个城市的距离, 无向图双向赋值
for (int i = 0; i < M; i++) {
int u, v, l;
cin >> u >> v >> l;
G[u][v] = G[v][u] = l;
}
dijkstra(C1);
cout << num[C2] << " " << w[C2] << endl;
}

Tsukkomi

  Dijkstra 基本快忘了,思想是明白的,但写出来有点费劲。之前用到的时候也是直接比着模板写的,但为了准备 PAT 考试,就硬学呗。代码参考了胡凡的《算法笔记》,书上正好有这道题的讲解,很是详细。


Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×