题目:https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376
代码:
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
typedef struct Node {
int v, w;
Node(int a, int b) :v(a), w(b) {}
}node;
const int INF = 0x3f3f3f3f;
const int MAXN = 600;
vector<int>vis(MAXN, 0); // 存储每个节点是否被访问
vector<int>dis(MAXN, INF); // 存储起始点到达每个节点的最短路径长度
vector<int>nums(MAXN, 0); // 存储每一个rescue teams的数量
vector<int>num_count(MAXN, 0); // 初始节点到每一个节点的最短路径数量
vector<int>max_count(MAXN, 0); // 对每一个节点获得最大的rescue teams
vector<vector<node>>G(MAXN); // 邻接表的方式存储无向图
int n, m, s, e;
//迪杰斯特拉算法
void dijkstra() {
//设置起始点的dis为0,且最短路径 s->s的方式只有一种
dis[s] = 0; num_count[s] = 1;
for (int i = 0; i < n; i++) {
int u = -1, mmin = INF;
//每一次选出最短距离的未访问过的节点
for (int j = 0; j < n; j++) {
if (vis[j] == 0 && dis[j] < mmin) {
u = j; mmin = dis[j];
}
}
if (u == -1) break;
vis[u] = 1;
//遍历该节点所能到达的节点,更新dis数组
for (int j = 0; j < G[u].size(); j++) {
int v = G[u][j].v, w = G[u][j].w;
//由于大于和等于的操作基本一致,因此写在一起
if (vis[v] == 0 && dis[v] >= dis[u] + w) {
if(dis[v] == dis[u] + w){
//到达v节点的路径数量会等于原来的数量加上从u到达的数量
num_count[v] += num_count[u];
//取可以获得的最大值
max_count[v] = max(max_count[v], max_count[u] + nums[v]);
}
else{
//修改dis[v]的长度
dis[v] = dis[u] + w;
num_count[v] = num_count[u];
max_count[v] = max_count[u] + nums[v];
}
}
}
}
}
int main() {
int a, b, c;
cin >> n >> m >> s >> e;
for (int i = 0; i < n; i++) cin >> nums[i];
// 无向图
for (int i = 0; i < m; i++) {
cin >> a >> b >> c;
G[a].push_back(Node(b, c));
G[b].push_back(Node(a, c));
}
for (int i = 0; i < n; i++) max_count[i] = nums[i];
dijkstra();
cout << num_count[e] << " " << max_count[e] << endl;
return 0;
}
解题思路:这题是一个迪杰斯特拉的原型题上加了一些其他的问题,整体上还是一个基于迪杰斯特拉算法解决的问题。首先是问多少条最短路径,这个时候就可以用普通的迪杰斯特拉算法来求解,只有当dis[v] == dis[u] + w的时候就加上u所有的最短路径数量,如果是dis[v] > dis[u] + w的情况,那么直接把u点的最短路径数量赋值过去就可以了。