题目地址
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.
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.
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.
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
2 4
开始以为是简单的最短路模板题,结果发现还是有点意思的,在简单的最短路的基础上更进一步,基础图论起手就是 Dijkstra。最短路基础算法 原地TP
和基础最短路不同的是,这里我们需要计算的是最短路的条数,以及这些最短路中节点权重和最大的值。可以作为其他类似题目的解题思路。
在基础的 Dijkstra 算法中我们每次更新对应点最短路当到此点距离小于到其相邻点距离与对应边权和,这样就保证每次都是“最短”了,显然最短路不只一条,那么何时可以判断有重复最短路。
简单来说 d [ i ] d[i] d[i] 表示起始点到i点的最短路大小,到C点的最短路更新在 d [ C ] < d [ B ] + c o s t d[C] < d[B] + cost d[C]<d[B]+cost 的时候。我们使用 n u m [ i ] num[i] num[i] 表示到i点最短路条数,此时到C的最短路只能是从点B过来,所以此时C的最短路数量就是B的最短路数量。 点C最短路条数增长仅当 d [ B ] + c o s t = = d [ C ] d[B] + cost == d[C] d[B]+cost==d[C] 时,这时候说明从B到C和C原来的最短路是一样的,所以我们需要把到B的最短路数量加给我们的C,得到新的最短路条数
代码表示如下:
// 更新C点的最短路
// B为C的所有邻点
for(B in C_Neighbor) {
if(d[B]+cost < d[C]) {
// 此时更新最短路 通过B到C 所以C的最短路数量等于到B的最短路数量
d[C] = d[B]+cost;
num[C] = num[B];
}
else if(d[B]+cost == d[C]) {
// 从B方向来的路也是最短路 所以加上
num[C] += num[B];
}
}
对于最短路中的最大节点权值和则比较简单,当存在更短的路径时,更新对应点的权值和,当存在相同长度最短路时,比较两条路的节点权值和,取较大的,最后的逻辑代码如下:
// 更新C点的最短路
// B为C的所有邻点
// sum[i] 表示i点的最短路径节点权值和最大值
for(B in C_Neighbor) {
if(d[B]+cost < d[C]) {
// 此时更新最短路 通过B到C 所以C的最短路数量等于到B的最短路数量
d[C] = d[B]+cost;
num[C] = num[B];
sum[C] = sum[B] + weight[C]; // weight[C] C节点的权值
}
else if(d[B]+cost == d[C]) {
// 从B方向来的路也是最短路 所以加上
num[C] += num[B];
if(sum[C] < sum[B] + weight[C]) {
sum[C] = sum[B] + weight[C];
}
}
}
注意其中对应数组变量的初始化
#include
#include
#include
#include
#include
#include
#define LOCAL
#define INF 0x3f3f3f3f
const int maxn = 501;
using namespace std;
typedef pair<int,int> P; // P.first 为 起始点到 P.second 的最短路
struct edge {int to, cost;};
vector<edge> G[maxn]; // 存储图的邻接矩阵
int d[maxn]; // 对应点的最短路
int team_num[maxn]; // 每个城市对应点的救援队数量
int road_sum[maxn]; // 最短路数量
int team_sum[maxn]; // 节点最大权值和
int main() {
#ifdef LOCAL
freopen("./in.txt", "r", stdin);
#endif
int n, m, s, t; scanf("%d %d %d %d", &n, &m, &s, &t);
fill(d, d+maxn, INF); d[s] = 0;
fill(road_sum, road_sum+maxn, 0); // 开始全部为 0
road_sum[s] = 1; // 起点到自己有1条路
for(int i = 0;i < n;i++) {
scanf("%d", team_num+i);
team_sum[i] = team_num[i]; // 都可以自己到自己,所以和team_num一样
}
// 读入图数据
int t_s, t_t, t_cost;
for(int i = 0;i < m;i++) {
scanf("%d %d %d", &t_s, &t_t, &t_cost);
G[t_s].push_back(edge{t_t, t_cost});
G[t_t].push_back(edge{t_s, t_cost});
}
priority_queue<P, vector<P>, greater<P> > que;
que.push(make_pair(0, s));
while (!que.empty()) {
P t = que.top(); que.pop();
if(d[t.second] < t.first) {
continue;
}
for(int i = 0;i < G[t.second].size();i++) {
edge e = G[t.second][i];
if(d[e.to] > d[t.second] + e.cost) {
team_sum[e.to] = team_sum[t.second] + team_num[e.to];
road_sum[e.to] = road_sum[t.second];
d[e.to] = d[t.second] + e.cost;
que.push(make_pair(d[e.to], e.to));
}
else if(d[e.to] == d[t.second] + e.cost) {
road_sum[e.to] += road_sum[t.second];
if(team_sum[e.to] < team_sum[t.second] + team_num[e.to]) {
team_sum[e.to] = team_sum[t.second] + team_num[e.to];
}
}
}
}
printf("%d %d", road_sum[t], team_sum[t]);
return 0;
}