这是题目,给各位翻译一下。现有一个城市群。每个城市都有自己的救援力量,每个城市之间的路途距离也有给出。现在你作为区域的救援队长,一旦出现紧急情况。你需要在最短的距离赶到救援现场,并尽可能从途中带走更多的救援力量到达救灾点。输入的第一行分别是:城市数(顶点数),城市之间的道路数(边数),救援队长出发点,事故发生点,第二行是每个城市的救援力量,接下来的边数行是边权值信息。每行对应着起点,终点,以及路途距离。输出是最短路径的数目和可以携带到的最大救援力量。
(我的解释喜欢写在代码里。算作注释。)
#include <iostream>
using namespace std;
const int MAXV = 1000;
const int INF = 1000000000;
int g[MAXV][MAXV]; //图的边值。未初始化的全局变量会自动初始化为0
bool vit[MAXV] = { false }; //判断是否已经访问过。
int d[MAXV]; //记录最短距离。
//这是常规的三个数组
int num[MAXV]; //记录到达这个顶点的最短路径的数量,默认初始化起点的值为1,其余为0
int weight[MAXV]; //记录该顶点的救援力量。主函数一开始就会由输入初始化。
int w[MAXV]; //记录到达该顶点的最大救援力量。
void Dijkstra(int n) {
for (int i = 0; i < n; i++) {
int u = -1; int MIN = INF;
for (int j = 0; j < n; j++) {
if (vit[j] == false && d[j] < MIN) {
u = j;
MIN = d[j];
}
}
if (u == -1) return;
vit[u] = true;
for (int v = 0; v < n; v++) {
if (vit[v] == false && g[u][v] != 0) {
if (d[u] + g[u][v] < d[v]) {
d[v] = d[u] + g[u][v];
//最小距离改进。还需要维护num数组和w数组。
num[v] = num[u]; //如果走u过,距离可以更短,那么v的数量就和u的数量相等。
w[v] = w[u] + weight[v]; //如果距离更近,直接选择这条路,不考虑稍微远的那条路是否有更大的救援力量。
//因为题意要求的就是尽快到达,之后再有尽可能多的救援力量。
}
else if(d[u]+g[u][v]==d[v]){
num[v] += num[u]; //如果一样远,那么v的数量就需要加上u的数量。
if (w[u] + weight[v] > w[v]) {
w[v] = w[u] + weight[v];
}
}
}
}
}
}
int main() {
int N, M;
int C1, C2;
fill(d, d + MAXV, INF);
cin >> N >> M >> C1 >> C2;
num[C1] = 1;
d[C1] = 0;
for (int i = 0; i < N; i++) {
cin>>weight[i];
}
w[C1] = weight[C1];
for (int i = 0; i < M; i++) {
int c, d1, e;
cin >> c >> d1 >> e;
g[c][d1] = g[d1][c] = e;
}
Dijkstra(N);
cout << num[C2] << " "<<w[C2];
return 0;
}
算法笔记还给出了更加模板化的写法。就是先用Dijkstra算法记录所有的最短路径(只考虑距离),然后再从这些路径里面选择出满足第二尺度的最优的路径。(第二尺度就是指点权啊,比如这里的救援力量,边权啊,比如走一条边的花费等等。)这里给出的方法是用DFS算法去找出满足第二尺度最优的路线。
#include <iostream>
#include <vector>
using namespace std;
const int MAXV = 1000;
const int INF = 1000000000;
int g[MAXV][MAXV]; //图的边值。
bool vit[MAXV] = { false }; //判断是否已经访问过。
int d[MAXV]; //记录最短距离。
//这是常规的三个数组
int num[MAXV]; //记录到达这个顶点的最短路径的数量,默认初始化起点的值为1,其余为0
int weight[MAXV]; //记录该顶点的救援力量。主函数一开始就会由输入初始化。
vector<int> pre[MAXV]; //这是一个数组,每个数组元素都是一个数组。
int optvalue=0;
vector<int> path, temppath; //记录最短的那个路径以及中间临时的路径。
void Dijkstra(int n) {
for (int i = 0; i < n; i++) {
int u = -1; int MIN = INF;
for (int j = 0; j < n; j++) {
if (vit[j] == false && d[j] < MIN) {
u = j;
MIN = d[j];
}
}
if (u == -1) return;
vit[u] = true;
for (int v = 0; v < n; v++) {
if (vit[v] == false && g[u][v] != 0) {
if (d[u] + g[u][v] < d[v]) {
d[v] = d[u] + g[u][v];
//最小距离改进。
pre[v].clear();
pre[v].push_back(u);
num[v] = num[u]; //如果走u过,距离可以更短,那么v的数量就和u的数量相等。
}
else if (d[u] + g[u][v] == d[v]) {
pre[v].push_back(u);
num[v] += num[u]; //如果一样远,那么v的数量就需要加上u的数量。
}
}
}
}
}
//重点是这里加的这个DFS1函数,这里来处理第二尺度。意思就是说把两个尺度的处理分开,使之更加的清晰可控,逻辑没那么复杂。
void DFS1(int C1,int C2) {
//先处理边界
if (C2 == C1) {
temppath.push_back(C2);
int value = 0;
for (int i = 0; i < temppath.size(); i++) {
value += weight[temppath[i]];
}
if (value > optvalue) {
optvalue = value;
path = temppath;
}
temppath.pop_back();
return;
}
temppath.push_back(C2);
for (int i = 0; i < pre[C2].size(); i++) {
DFS1(C1, pre[C2][i]);
}
temppath.pop_back();
}
int main() {
int N, M;
int C1, C2; //起点和终点
fill(d, d + MAXV, INF);
cin >> N >> M >> C1 >> C2;
num[C1] = 1;
d[C1] = 0;
for (int i = 0; i < N; i++) {
cin >> weight[i];
}
for (int i = 0; i < M; i++) {
int c, d1, e;
cin >> c >> d1 >> e;
g[c][d1] = g[d1][c] = e;
}
Dijkstra(N);
DFS1(C1, C2);
cout << num[C2] << " "<<optvalue;
return 0;
}
好了,以上就是这道题的代码以及思想。谢谢阅读!