1. 程式人生 > 實用技巧 >[PAT] A1018 Public Bike Management

[PAT] A1018 Public Bike Management

題目大意

給出需要調整的車站編號,從0處出發,一路上順便調整途徑的車站,使得每個車站的車輛數是Cmax的一半,多的帶走少的補齊。選最短路,最短相同選從0處帶的車最少的路,若還相同則選擇帶回0處的車最少的路。
輸出要帶的車輛數,路徑,帶回的車輛數(返回時直接回,不再調整)。

思路

題目生詞

figure
n. 數字
v. 認為,認定;計算;是……重要部分

The stations are represented by vertices and the roads correspond to the edges.
頂點表示車站,邊表示道路。

correspond to 相當於

capacity
n. 能力;容量

方法

Dijkstra + DFS。先用Dijkstra演算法算出最短路徑,只考慮時間最短,建立vector儲存路徑的前驅節點。然後用DFS遍歷每一條路徑,獲得一條路徑後(即遍歷到了起始節點0)計算帶去帶回的車輛,確定最佳方案。
計算帶去、帶回車輛數的方法:對於每個站點,考慮前一個站點傳遞下來的車輛數trans和自己的車輛數bike[i]相加的結果與cmax/2的差,分兩種情況——一,差值為負,即車不夠,要從0處帶車,所以bring的值增加其差值的絕對值,而傳遞給下去的車輛數trans置為0;二,差值非負,表示車夠了,多出的車賦值給trans傳遞到下一個站點,bring的值保持。一開始bring和trans的值為0,從出發節點的下一個節點(即0號節點的下一個節點)開始遍歷計算。最終bring為要從0處攜帶的車輛數,trans即帶回的車輛數。注意,有關從0處帶多少車,只與當前走過的車站有關,即不管後面站點車再多,前面的車不夠了,就要從0處帶(因為走路不會回頭,攜帶的車輛數是隨著路徑的推進而變化的)。而DFS是從終點向前推到起點結束,則必須要求完整條路徑才能算的出來。最後倒著輸出變長陣列的值,即為路徑。

tips

要熟練運用Dijkstra+DFS求最佳路徑的演算法!

AC程式碼

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
using namespace std;
#define N 502
#define INF 100000000
int cmax, stations, goal, roads;
int bike[N];
int length[N][N] = { {0} };
bool vis[N] = {};
int d[N];
vector<int>pre[N], path, bestpath;
int minbring = INF, minback = INF; 
void DFS(int v)
{
    if (v == 0){ //到邊界--起始節點。
         //計算第二、三標尺的值,即帶去、帶回的車輛數。
         path.push_back(v);
         int bring = 0, trans = 0;
         for (int i = path.size() - 2; i >= 0; i--) {//倒著來才是路徑的正序
             int  u = path[i];
             if (bike[u] + trans >= cmax / 2) 
                 trans += bike[u] - cmax / 2;
             else {
                 bring += cmax / 2 - bike[u] - trans;
                 trans = 0;
             }
         }
         //更新最優值。
         if (bring < minbring) {
             bestpath = path;
             minbring = bring;
             minback = trans;
         }
         else if (bring == minbring) {
             if (trans < minback) {
                 bestpath = path;
                 minback = trans;
             }
         }
         path.pop_back();
         return;
    }
     path.push_back(v);
     for (int i = 0; i < pre[v].size(); i++)        
         DFS(pre[v][i]);
     path.pop_back();
}
void Dijkstra(int s)
{
     int i, j;
     fill(d, d + N, INF);
     d[s] = 0;
     for (i = 0; i <= stations; i++) { //找不在s集中的d最小
         int min = INF, u = -1;
         for (j = 0; j <= stations; j++) {
             if (min > d[j] && vis[j] == 0) {
                 min = d[j];
                 u = j;
             }
         }
         if (u == -1)return;
         vis[u] = true;
         //對於通過u能到s的點v,更新路徑
         for (j = 0; j <= stations; j++) {
             if (length[u][j] && vis[j] == 0) {
                 if (d[u] + length[u][j] < d[j]) {
                     d[j] = d[u] + length[u][j];
                     pre[j].clear();
                     pre[j].push_back(u);
                 }
                 else if (d[u] + length[u][j] == d[j]) 
                     pre[j].push_back(u); 
             }
         }
     }
}
int main()
{
     cin >> cmax >> stations >> goal >> roads;
     int i;
     for (i = 1; i <= stations; i++)
         cin >> bike[i];
     for (i = 0; i < roads; i++) {
         int u, v;
         cin >> u >> v;
         cin >> length[u][v];
         length[v][u] = length[u][v];
     }
     Dijkstra(0);
     DFS(goal);
     cout << minbring << " 0";
     for (i = bestpath.size() - 2; i >= 0; i--)
         cout << "->" << bestpath[i];
     cout << " " << minback;
     return 0;
}