[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; }