地图上有一些分散的城市,这些城市通过一些双向道路相连。地图上标出了每个城市的救援队数量以及每对城市之间的每条道路的长度。当从其他城市接到紧急电话时,你需要尽快到达该城市,同时在途中尽可能多地召集救援队。
输入第一行包含 4 个正整数:N、M、C1、C2,分别表示城市数量(城市从 0 到 N-1 编号)、道路数量、当前所在的城市和要到达的城市。接下来一行包含 N 个整数,其中第 i 个整数是第 i 个城市中救援队的数量。接下来 M 行,每行以$c_1,c_2,L$的格式描述一条道路,其中$c_1,c_2,L$分别是该条道路相连的一对城市编号以及该道路的长度。题目保证从 C1 到 C2 至少存在一条路径。
在一行打印两个数字:C1 和 C2 之间最短路径的数量以及可能聚集的最大救援队数量。一行中的所有数字必须完全由一个空格隔开,并且在行尾不允许有多余的空格。
本题是经典的 Dijkstra 算法变形问题,建议系统学习过 Dijkstra 算法及其相关变形技巧之后再尝试解决本题。
#include <bits/stdc++.h>
using namespace std;
using gg = long long;
struct Edge {
gg to, cost;
Edge(gg t, gg c) : to(t), cost(c) {}
};
const gg MAX = 505;
vector<vector<Edge>> graph(MAX);
vector<gg> city(MAX), dis(MAX, INT_MAX), pathNum(MAX), teamNum(MAX);
gg ni, mi, c1, c2;
using agg2 = array<gg, 2>;
void Dijkstra(gg s) {
priority_queue<agg2, vector<agg2>, greater<agg2>> pq;
dis[s] = 0;
pathNum[s] = 1;
teamNum[s] = city[s];
pq.push({0, s});
while (!pq.empty()) {
auto p = pq.top();
pq.pop();
if (dis[p[1]] != p[0]) {
continue;
}
for (auto& e : graph[p[1]]) {
if (dis[e.to] > p[0] + e.cost) {
dis[e.to] = p[0] + e.cost;
pq.push({dis[e.to], e.to});
pathNum[e.to] = pathNum[p[1]];
teamNum[e.to] = teamNum[p[1]] + city[e.to];
} else if (dis[e.to] == p[0] + e.cost) {
pathNum[e.to] += pathNum[p[1]];
teamNum[e.to] = max(teamNum[p[1]] + city[e.to], teamNum[e.to]);
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> ni >> mi >> c1 >> c2;
for (gg i = 0; i < ni; ++i) {
cin >> city[i];
}
for (gg i = 0; i < mi; ++i) {
gg a, b, c;
cin >> a >> b >> c;
graph[a].push_back(Edge(b, c));
graph[b].push_back(Edge(a, c));
}
Dijkstra(c1);
cout << pathNum[c2] << " " << teamNum[c2];
return 0;
}