markdown 文章内容
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2

输出样例:

2 60
0 1 3

其实就是dijkstra算法,固定套路+根据题意添加变量做修改。
只是数据量稍微多些,我把数据量分为了三类。
1.输入 2. 输出3. 固定套路数据量
记住算法中固定套路的数据量比如d[maxn] ,vis[maxn],w[maxn]等再根据题意添加数据量这样会简单些。
具体思路:
首先分析题目明确目的,要求输出最短路径条数,还要能够召集最多的救援队数量,还有输出经过的城市编号。

接下来开始求解。从起点,找距离最近的城市点u,找到后标记u已被访问,确定u作为中转站,通过d[v] > d[u] + G[u][v]更新dv;反复重复n次,直到所有城市点都被标记。这就是一般dijskra大致思路再结合目的细化考虑。
==最短路径条数,召集最多救援队数量,记录前结点==都应该伴随在更新dv的步骤后。更新dv条件:d[v] <d[u] + G[u][v] || (d[v] == d[u] + G[u][v] && w[v] < w[u] + weight[v]

最后,深度遍历输出
注意: 要记得d[maxn] 、G[maxn][maxn]初始化为INF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory>
using namespace std;
const int maxn = 550; //最大城市数量
const int INF = 0x3fffffff;
//思考整个过程需要哪些量
//首先明确输入的量有哪些
int n, m, s, e;//城市数量 道路条数 出发点 终点
int G[maxn][maxn], weight[maxn]; //G两点间道路长度(无向路) weight存储城市救援队数量
//求解的量
int num[maxn], w[maxn], pre[maxn];//d起始点到各点的最短距离 num源点到各点的路径条数 w源点到各点能够召集最多的救援队数量
//图中一般都需要的量
int d[maxn];//d起始点到各点的最短距离
bool vis[maxn] = {false};//用于判断是否访问过
void dijkstra(int s)
{
//初始化
fill(d, d + maxn, INF);
fill(w, w + maxn, 0);
d[s] = 0;
num[s] = 1; //s到s点数目为1
w[s] = weight[s];
for(int i = 0; i < n; i++)//找距离源点最近的点 找n次
{
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为中转点 更新的[v];
for(int v = 0; v < n; v++)
{
if(vis[v] == false && d[v] > d[u] + G[u][v])
{
d[v] = d[u] + G[u][v];
num[v] = num[u];//继承源点到u的道路数目
w[v] = weight[v] + w[u];
pre[v] = u;
}
else if(vis[v] == false && d[v] == d[u] + G[u][v])
{
num[v] = num[u] + num[v];
//距离一样那就要看谁的权值大 大就更新
if(w[u] + weight[v] > w[v])
{
w[v] = weight[v] + w[u];
pre[v] = u;
}
}
}
}
}
void dfs(int v)
{
if(v == s)
{
cout << s;
return;
}
else
{
dfs(pre[v]);
cout <<" " << v;
}
}
int main()
{
fill(G[0],G[0] + maxn*maxn, INF);
cin >> n >> m >> s >> e;
for(int i = 0; i < n; i++)
{
cin >> weight[i];
}
while(m--) //输入的是道路条数对应的是m
{
int u, v;
cin >> u >> v;
cin >> G[u][v];
G[v][u] = G[u][v];
}
dijkstra(s);
cout << num[e] << " " << w[e] << endl;
dfs(e);
return 0;
}