L2-001 緊急救援

題解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;
}
相關文章
相關標籤/搜索