原文链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376
思路
这道题有两个标尺,第一标尺是距离,第二标尺是点权。而且需要求最短路径的条数。这种问题的处理方法见《算法笔记》P377
新增点权和求最短路径条数
新增点权
用weight[u]表示城市的物资收入,并增加一个数组w[],令起点s到顶点u可以收集到的最大的物资是w[u],初始化w[s]=weight[s]。
求最短路径条数
增加一个num[],初始化num[s]=1,其余num[]都为0。
for (int v = 0; v < n ; v++) {
//如果v未访问 && u能到达v
if (vis[v] == false && G[u][v] != Inf) {
if (d[u] + G[u][v] < d[v]) { //以u为中继点更优
d[v] = d[u] + G[u][v];
w[v] = w[u] + weight[v];
num[v] = num[u];
}
else if (d[u] + G[u][v] == d[v] ) {
if(w[u]+weight[v]>w[v])
w[u] + weight[v] > w[v];
//最短路径条数与点权无关,必须写在外面
num[v] += num[u];
}
}
}
代码
#include <iostream>
#include <string>
#include <set>
#include <map>
#include<queue>
#include<stack>
#include<algorithm>
//new and delete
//A1003 Emergency
using namespace std;
const int MaxN = 1000;
const int Inf = 0x3fffffff;
int teams_num[MaxN] = { 0 };
int G[MaxN][MaxN] ;
//路径长度相同选择走过救援队最多的
int d[MaxN]; //最短距离
int d_n[MaxN]; //最短路径条数
int team_get[MaxN]; //走过的路线救援队
bool vis[MaxN] = { false };
void PrintN(int a[],int N) {
cout << "数组: "<< endl;
for (int i = 0; i < N; i++)
cout << a[i] << " ";
cout << endl;
}
//s为源点的最短路, N为结点数
void Dijkstra(int s,int N) {
fill(d, d + MaxN, Inf);
fill(vis, vis + MaxN, false);
d[s] = 0;
d_n[s] = 1; //最短路径条数
team_get[s] = teams_num[s];
for (int i = 0; i < N; i++) {
//找出未访问的结点中d[]最小的u
int u = -1, Min = Inf;
for (int j = 0; j < N; j++) {
if (vis[j] == false && d[j] < Min) {
u = j;
Min = d[j];
}
}
//如果不连通
if (u == -1) return;
vis[u] = true;
//以u为中继结点更新d[], d_n[], team_get[]
for (int j = 0; j < N; j++) {
if (vis[j] == false && G[u][j] != Inf) {
if (d[u] + G[u][j] < d[j]) { //得到更短的路
d[j] = d[u] + G[u][j];
d_n[j] = d_n[u];
team_get[j] = team_get[u] + teams_num[j];
}
else if (d[u] + G[u][j] == d[j]) { //相同的路径, 更新最短路条数和得到救援队数
d_n[j] = d_n[u] + d_n[j];
if (team_get[j] < team_get[u] + teams_num[j])
team_get[j] = team_get[u] + teams_num[j];
}
}
}
}
}
int main() {
//数组初始化
fill(d, d + MaxN, Inf);
fill(G[0], G[0] + MaxN * MaxN, Inf);
fill(d_n, d_n + MaxN, 0);
fill(team_get, team_get, 0);
//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
int N, M, C1, C2;
cin >> N >> M >> C1 >> C2;
for (int i = 0; i < N; i++)
cin >> teams_num[i];
for (int i = 0; i < M; i++) {
int ca, cb, L;
cin >> ca >> cb >> L;
G[ca][cb] = G[cb][ca] = L;
}
Dijkstra(C1,N);
//
PrintN(d, N);
PrintN(d_n, N);
PrintN(team_get, N);
//
//output
cout << d_n[C2] << " " << team_get[C2] << endl;
return 0;
}