題解ios
該題考察最短路問題,採用 dijkstra 算法,並在其基礎上進行擴展。算法
首先是路徑打印,須要記錄該點具體由上一個(哪個點)轉移過來的,用 $path[]$ 數組記錄(具體在更新循環中)。數組
如上圖。網絡
敲重點spa
關於如何求解路徑條數和對應最短路徑下的最多救援隊數量,咱們先看下圖3d
設 $su[i]$ 表示從 $s$ (起點)到 $i$ 點最短距離救援隊數量的最大值,$dist[i]$ 表示從 $s$ (起點)到 $i$ 點的最短距離,採用鄰接矩陣 $g$ 存儲全部的邊,$num[i]$ 存儲 $s$(起點)到 $i$ 點最短路徑的條數。code
知足 dist[j] <= dist[t] + g[t][j] 的狀況下,咱們分兩種狀況進行討論blog
一、dist[j] == dist[t] + g[t][j]ci
>則距 j 點對應的最短距離是不變的,此時數量對其取 max 便可。string
>路徑很顯然增長 num[t](可由 t 擴展)。
二、dist[j] < dist[t] + g[t][j]
>則需更新最短距離,由此路徑一定爲通過 t 再通過由 t 到 j 的邊,此時的數量更新爲 su[t] + c[j](c[j] 表示 j 點對應救援隊的數量)。
>路徑也必須更新至 t 對應的最短路徑的條數。
記得初始 num[s] = 1,即本身到本身的一條路徑。
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int N = 510; int n, m, s, d, ans; int g[N][N], dist[N], c[N], path[N], num[N], p[N]; int su[N]; bool st[N]; void dijkstra() { memset(dist, 0x3f, sizeof(dist)); dist[s] = 0; for (int i = 0; i < n; ++i) { int t = -1; for (int j = 0; j < n; ++j) { if (!st[j] && (t == -1 || dist[t] > dist[j])) { t = j; } } st[t] = true; for (int j = 0; j < n; ++j) { if (dist[j] >= dist[t] + g[t][j]) { if (dist[j] == dist[t] + g[t][j]) { num[j] += num[t]; if (su[j] < su[t] + c[j]) { su[j] = su[t] + c[j]; path[j] = t; } } else { num[j] = num[t]; su[j] = su[t] + c[j]; path[j] = t; dist[j] = dist[t] + g[t][j]; } } } } int last = d; while (last != s) { p[ans++] = last; last = path[last]; } p[ans++] = last; cout << num[d] << " " << su[d] << endl; for (int i = ans - 1; i >= 0; --i) { if (i == 0) { cout << p[i] << endl; } else { cout << p[i] << " "; } } } int main() { cin >> n >> m >> s >> d; memset(g, 0x3f, sizeof(g)); for (int i = 0; i < n; ++i) { // 城市救援隊數量 cin >> c[i]; su[i] = c[i]; } for (int i = 0; i < m; ++i) { // 城市網絡結構 int a, b, w; cin >> a >> b >> w; g[a][b] = g[b][a] = w; } // 由於由 s 點出發 num[s] = 1; dijkstra(); return 0; }