PAT - 甲級 - 1018 Public Bike Management
阿新 • • 發佈:2020-07-14
Nothing to fear
種一棵樹最好的時間是十年前,其次是現在!
那些你早出晚歸付出的刻苦努力,你不想訓練,當你覺的太累了但還是要咬牙堅持的時候,那就是在追逐夢想,不要在意終點有什麼,要享受路途的過程,或許你不能成就夢想,但一定會有更偉大的事情隨之而來。 mamba out~
2020.7.14
人一我十,人十我百,追逐青春的夢想,懷著自信的心,永不言棄!
Public Bike Management
考點: Dijkstra求最短路,Dijkstra記錄最短路徑,dfs,閱讀理解
題目大意
給定一個起點PBMC,和一個終點SP,求出從PBMC 到 Sp的最短路徑(如果不止一條則都要記錄下來),從中挑選出一條,從PBMC需要傳送的車輛最少的那一條路徑,如果遇到重複則輸出需要將自行車返回回去的儘可能少的那一條(題目確保該路徑唯一)。
分析
1.如何記錄在Dijkstra中所求得得最短路徑,由於Dijkstra時基於貪心思想當你要利用某一個頂點 x 去鬆弛其他頂點時,x之前得結點已經被確定,換句話說就是每當你確定一個點,這個點得前一個點一定已經被確定,雖然聽起來像廢話但是還是需要去好好考慮的!故我們可以用一個容器來存在某個點的前一個點來記錄路徑
定義一個容器vector<int> pre[N]; 用於存放結點的所確定的前一個結點有哪些 while(!q.empty()) { int x = q.top().second;q.pop(); if(vis[x])continue; vis[x] = 1; for(int i = 1;i <= n;i ++) { int y = i , w = e[x][i]; if(dis[y] > dis[x] + w) // 更新 x -> y { pre[y].clear(); pre[y].push_back(x); dis[y] = dis[x] + w; q.push({-dis[y] , y}); }else if(dis[y] == dis[x] + w){ pre[y].push_back(x); } } }
2.得到路徑之後需要對路徑進行dfs檢查所需要傳送/放回都達到最優的那一條路!
需要注意的點:
- 認真讀題
- 如何記錄Dijkstra的最短路徑的結點需要熟記利用記錄前一個結點的pre容器!
完整程式碼
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; const int N = 1005; int Cmax , n , m , sp , mid , minsent = 0x3f, mintake = 0x3f; int e[N][N] , dis[N] , carry[N]; bool vis[N]; priority_queue<pair<int,int> > q; vector<int> pre[N] , path; void dfs(vector<int> tmp, int now) { if(now == 0) { int need = 0 , back = 0; for(int i = tmp.size() - 1;i >= 0;i --) { int id = tmp[i]; if(carry[id] > 0) back += carry[id]; else{ if(back > (0 - carry[id])) back += carry[id]; else{ need += (0 - carry[id] - back); back = 0; } } } if(need < minsent){ minsent = need; mintake = back; path = tmp; } if(need == minsent && back < mintake) { mintake = back; path = tmp; } } for(int i = 0;i < pre[now].size();i ++) { tmp.push_back(now); dfs(tmp, pre[now][i]); tmp.pop_back(); } } void Dijkstra() { memset(dis , 0x3f , sizeof dis); memset(vis , 0 ,sizeof vis); dis[0] = 0; // 規定PBMC 為頂點 0 q.push({0 , 0}); while(!q.empty()) { int x = q.top().second;q.pop(); if(vis[x])continue; vis[x] = 1; for(int i = 1;i <= n;i ++) { int y = i , w = e[x][i]; if(dis[y] > dis[x] + w) // 更新 x -> y { pre[y].clear(); pre[y].push_back(x); dis[y] = dis[x] + w; q.push({-dis[y] , y}); }else if(dis[y] == dis[x] + w){ pre[y].push_back(x); } } } vector<int> t;dfs(t, sp); } int main() { memset(e , 0x3f , sizeof e); for(int i = 0;i <= n;i ++)e[i][i] = 0; cin >> Cmax >> n >> sp >> m; mid = Cmax / 2; for(int i = 1;i <= n;i ++) scanf("%d",&carry[i]) , carry[i] = carry[i] - mid; int a, b ,c; for(int i = 0;i < m;i ++) { scanf("%d %d %d", &a ,& b, &c); e[a][b] = e[b][a] = c; } Dijkstra(); cout << minsent << " 0"; for(int i = path.size() - 1;i >= 0;i --) { printf("->%d", path[i]); } cout << " " << mintake << endl; return 0; }