L2-001 緊急救援-團體程序設計天梯賽GPLT

題目來源:團體程序設計天梯賽-練習集
題目地址:L2-001 緊急救援

題目描述L2-001

題目大意

題目給出一張圖,其中包括道路連接的城市和它們的距離,以及每個城市救援隊的數量,最後求從出發地城市到目的地城市的最短路徑條數、經過城市能召集到的最多救援隊數量和最後選擇的路徑,可以結合樣例理解題意:
1

題目分析

其實這道題目就是常規的最短路徑題目,和模板有所不同的是,在求最短路徑還要兼顧救援隊的數量和統計最短路徑條數。主要需要理解以下兩種情況下的統計:

  • 當找更短的路徑,即dis[v] > dis[u] + E[u][i].second時,
    因爲經過城市 uu 去城市 vv 是更優方案,所以在先前肯定沒有統計到這條路徑上的救援隊數量,所示直接用到城市 uu 後總的救援隊數量加上城市 vv 的救援隊數量。

    此時 uuvv 之間只有一條邊相連,所以到 vv 的最短路徑數也就等於到 uu 的最短路徑數。 如下圖所示,到城市 ee 的最短路徑數,不會因爲和城市 55 之間的一條路徑增加,所以等於到城市 55 的最短路徑數,即 total[e]=total[5]total[e] = total[5]

2

  • 當找到與最短路徑相等的路徑,即dis[v] == dis[u] + E[u][i].second時,
    需要判斷能否在這個城市召集到更多的救援隊,如果可以則更新救援隊數量和經過的路徑。

    由於是找到了長度一樣的路徑,相當多了一套到 vv 的方案,所以到城市 vv 總的最短路徑數是要多加上到點 uu 的最短路徑數(total[u]total[u]。如下圖所示,例如從 ssee ,除了經過城市 55 以外,又發現了經過城市 66 且距離相同的路,那麼結果應該要加上到城市 66 的最短路徑數量(total[6]total[6]), 所以最終 total[e]=total[5]+total[6]total[e] = total[5] + total[6]
    3

代碼如下

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f;
const int maxn =550;
int n, m, s, d;
/**
  * w[i]表示i城市擁有的救援隊數量
  * sum[i]表示走到i城市可以召集到的救援隊總數
  * total[i]表示走到i城市的路線數量
  */
int w[maxn], sum[maxn], total[maxn];
/**
  * dis[i]表示從源點到i點的最短距離
  * path[i]表示到i點的前驅節點
  */
int dis[maxn], vis[maxn], path[maxn];
vector<pii> E[maxn];

/**
  * 用dijstra算法求最短路徑
  */
void dijstra(int s) {
    memset(vis, 0, sizeof(vis));
    //pair比較大小默認是先比較first,所以這裏用first表示到源點的距離
    //改變優先隊列的優先級,讓到源點距離短的節點優先級高
    priority_queue<pii, vector<pii>, greater<pii> > q;
    // 初始化
    for (int i = 0; i < n; i++) dis[i] = inf;
    dis[s] = 0;
    sum[s] = w[s];
    total[s] = 1;
    q.push(pii(dis[s], s));
    while (!q.empty()) {
        int u = q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = 0; i < E[u].size(); i++) {
            int v = E[u][i].first;
            if (dis[v] > dis[u] + E[u][i].second) {
                dis[v] = dis[u] + E[u][i].second;
                //直接加上該城市的救援隊數量即可
                sum[v] = sum[u] + w[v];
                total[v] = total[u];
                path[v] = u;
                q.push(pii(dis[v], v));
            } else if (dis[v] == dis[u] + E[u][i].second) {
            	//如果在路徑長度相等的情況下,該路徑救援隊數量更多
                if (sum[v] < sum[u] + w[v]) {
                	//更新救援隊數量
                    sum[v] = sum[u] + w[v];
                    path[v] = u;
                }
                total[v] += total[u];
            }
        }
    }
}
/**
  * 用於輸出經過的路徑
  */
void output(int s, int d) {
    if (s == d) {
        printf("%d", s);
        return ;
    } else {
        output(path[s], d);
        printf(" %d", s);
    }
}

int main()
{
    scanf("%d %d %d %d", &n, &m, &s, &d);
    for (int i = 0; i < n; i++) scanf("%d", &w[i]);
    for (int i = 1; i <= m; i++) {
        int x, y, t;
        scanf("%d %d %d", &x, &y, &t);
        //由於是無向圖,所以兩個方向的邊都要加上
        E[x].push_back(pair<int, int>(y, t));
        E[y].push_back(pair<int, int>(x, t));
    }
    dijstra(s);
    printf("%d %d\n", total[d], sum[d]);
    output(d, s);
    return 0;
}


如果本文對你有所幫助,別忘了點贊哦~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章