#include <bits/stdc++.h>
using namespace std;
const int N = 1000;
int g[N][N]; // 记录两条路之间的距离
int cnt[N]; // 通往这条路的最短路的条数
int sum[N]; // 到该点最短路的救援队的数目
int pre[N]; // 记录前驱结点
bool visit[N]; // 记录该点是否已经访问过(false 为没访问过,true 则相反)
int a[N]; // 记录每个城市救援队的数目
int dist[N]; // 记录起始点到该点的距离
int n, m, s, d; // n 是城市的个数 m 是快速道路的条数 s 是出发地的城市编号 d 是目的地的城市编号
void Dijkstra()
{
memset(dist, 0x3f, sizeof(dist));
sum[s] = a[s]; // 初始化,sum[s]为0,应该等于起点的救援队数目
cnt[s] = 1; // 初始化起点到起点算1条路
dist[s] = 0; // 初始化起点到起点的距离为0
for(int i = 0; i < n; i ++) // 遍历所有点
{
int t = -1; // 用于存储dist最小的点
for(int j = 0; j < n; j ++) // 遍历所有dist的值
{
if(!visit[j] && (t == -1 || dist[t] > dist[j]))
{
t = j;
}
}
visit[t] = true; // 讲选中的点设置为true
for(int j = 0; j < n; j ++) // 遍历j点(起点到该点的距离)与t点(已经是起点到该点距离)的距离的最短路径
{
if(dist[j] > dist[t] + g[t][j]) // j点的距离 大于 t点的起点到该点距离 + t到j的距离
{
pre[j] = t; // 更新j的前驱结点
sum[j] = sum[t] + a[j]; // 更新起点到j点的救援队的数目
cnt[j] = cnt[t]; // 更新起点到j点的条数
dist[j] = dist[t] + g[t][j]; // 更新起点到j点的距离
}
else if(dist[j] == dist[t] + g[t][j]) // j点的距离 等于 t点的起点到该点距离 + t到j的距离
{
cnt[j] += cnt[t]; // 更新起点到j点的条数
if(sum[j] < sum[t] + a[j]) // 起点到j点的救援队的数目 小于 起点到t点的救援队的数目 + j点自身的救援队数目
{
sum[j] = sum[t] + a[j]; // 更新起点到j点的救援队的数目
pre[j] = t;// 更新j的前驱结点
}
}
}
}
cout << cnt[d] << " " << sum[d] <<endl;
int k = d;
stack<int> stk; // 利用栈来存储最短路
while(k != s)// 利用先进后出的特点,从终点开始,一次存入该点的前驱结点
{
stk.push(k); // 先存入自己本身
k = pre[k]; // 更新为前驱结点
}
cout << s; // 因为循环条件的原因,起点没有存入,我们需要额外输出起点
while(stk.size()) // 依次输出栈点元素
{
cout << " " <<stk.top();
stk.pop(); // 将栈顶元素弹出
}
}
int main()
{
memset(g, 0x3f, sizeof g);
cin >> n >> m >> s >> d; // 题目输入
for(int i = 0; i <n; i ++)
{
cin >> a[i]; // 输入每个城市救援队的数目
}
while(m --)
{
int a, b, c; // a 城市1 b 城市2 c 城市1和城市2之间的距离
cin >> a >> b >> c;
g[a][b] = g[b][a] = c; // 讲数据存入表中g[参数一][参数二] 表示参数一 到 参数二的距离
}
Dijkstra();
return 0;
}
dijkstra最短路求法(非原创,打卡专用)
有错的话,希望大家提醒。有更好做法,欢迎交流。