参考网络上代码,加上一些理解注释,主要算法为Dijkstra
Dijkstra的三个基本数组visit[] disc[] path[]
在加上新需求记录“最短路径条数”和“救援队伍数目”
#include <iostream>
#include <string>
#include <cstdio>
#include <iomanip>
#include <vector>
#include <algorithm>
using namespace std;
#define INF 1000 // 题目已知最大不超过500
int main()
{
int N, M, S, D;
cin >> N >> M >> S >> D;
int Team[N]; // 保存每个城市的救援队伍数目
for (int i = 0; i < N; ++i)
{
cin >> Team[i];
}
int map_in[N][N]; // 城市间地图数据
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j) // 默认初始化为最大值
map_in[i][j] = INF;
}
// 接收输入城市间路径(图)
for (int i = 0; i < M; ++i)
{
int pos_r, pos_c, cost;
cin >> pos_r >> pos_c >> cost;
map_in[pos_r][pos_c] = map_in[pos_c][pos_r] = cost;
}
// 下面执行Dijkstra最短路径算法(当最短路径出现多条时,比较救援队伍,从而决定下一个节点)
bool visit[N]; // 标记城市是否已访问过
int path[N]; // 记录路径
int disc[N]; // 记录城市最短距离
int teamnum[N]; // 记录队伍数目
int pathnum[N]; // 记录最短路径数目(有可能多条最短路径)
// 初始化
for (int i = 0; i < N; ++i)
{
visit[i] = false;
pathnum[i] = 0;
disc[i] = 0;
teamnum[i] = 0;
path[i] = 0;
}
visit[S] = true;
pathnum[S] = 1;
disc[S] = 0;
teamnum[S] = Team[S];
// 先处理与起始点相连接的顶点城市
for (int i = 0; i < N; ++i)
{
disc[i] = map_in[S][i];
if (map_in[S][i] != INF && i != S)
{
path[i] = S;
teamnum[i] = Team[i] + Team[S];
pathnum[i] = 1; // 此时最短路径认为只有一条
}
}
// 对剩余N-1个城市进行处理
for (int i = 1; i < N; ++i)
{
int min_dis = INF;
int u = S;
// 找出最短距离
for (int j = 0; j < N; ++j)
{
if (visit[j] == false && disc[j] < min_dis)
{
min_dis = disc[j];
u = j;
}
}
// 找出中间节点
visit[u] = true;
// 根据中间节点更新disc数组(最短距离)
for (int j = 0; j < N; ++j)
{
if (false == visit[j]) // 未纳入最短路径
{
if (disc[j] > min_dis + map_in[u][j]) // 加入中间节点后,路径缩短,则更新
{
disc[j] = min_dis + map_in[u][j]; // 更新距离
path[j] = u; // 更新路径
pathnum[j] = pathnum[u]; // 更新最短路径数目(最短路径未增加)
teamnum[j] = teamnum[u] + Team[j]; // 更新救援队伍(此处小心)
} else if (disc[j] == min_dis + map_in[u][j]) // 此时出现了另一条最短路径
{
pathnum[j] = pathnum[j] + pathnum[u]; // 最短路径条数相加
// 最短路径相同,再比较救援队伍数目
if (teamnum[j] < teamnum[u] + Team[j]) // 选择救援队伍多的一条
{
teamnum[j] = teamnum[u] + Team[j];
path[j] = u;
}
}
}
}
}
// 已处理完起始点S到其他任意节点的最短路径且最大救援队伍数目
// 此时path[]中记录着起始点S到其余各节点的最短路径
int pos(0);
int out_path[N];
int cur = D; // 从目的地查找到起始点S的路径
while(cur != S)
{
out_path[pos++] = cur; // 记录从D->S的路径
cur = path[cur]; // 找路径上的父节点
}
out_path[pos] = S; // 最后一个为起始点
cout << pathnum[D] << " " << teamnum[D] << endl;
for (int i = pos; i > 0; --i)
{
cout << out_path[i] << " ";
}
cout << out_path[0] << endl;
return 0;
}