這是題目,給各位翻譯一下。現有一個城市羣。每個城市都有自己的救援力量,每個城市之間的路途距離也有給出。現在你作爲區域的救援隊長,一旦出現緊急情況。你需要在最短的距離趕到救援現場,並儘可能從途中帶走更多的救援力量到達救災點。輸入的第一行分別是:城市數(頂點數),城市之間的道路數(邊數),救援隊長出發點,事故發生點,第二行是每個城市的救援力量,接下來的邊數行是邊權值信息。每行對應着起點,終點,以及路途距離。輸出是最短路徑的數目和可以攜帶到的最大救援力量。
(我的解釋喜歡寫在代碼裏。算作註釋。)
#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;
}
好了,以上就是這道題的代碼以及思想。謝謝閱讀!