開啟章節選單
10436 Cheapest way
題目連結
題目翻譯
孟加拉一間運輸公司「Moutushi Enterprise」想重新規劃公車路線,並向乘客收取合理車資。公車每行駛 1 公里要耗費 2 taka(孟加拉貨幣)的油錢,每經過一個車站也要支付該站的過路費;公司會在總成本上加收 10% 的利潤,再把總金額除以該班公車的座位數,即為每位乘客需負擔的車資。給定城市地圖(車站名稱與過路費、站與站之間的道路與距離),請對每筆查詢找出成本最低的路徑,並計算每位乘客需要負擔的車資。
輸入
第一行是地圖(測資)數量。每個地圖分三部分:第一部分第一行是車站數 nStation(0 < nStation < 20),接下來 nStation 行是「車站名稱 過路費」;第二部分第一行是道路數 nPath(0 < nPath < 20),接下來 nPath 行是「station1 station2 distance」(雙向道路,距離單位為公里);第三部分第一行是查詢數 nQuery(0 < nQuery < 10),接下來 nQuery 行是「station1 station2 passenger」。保證每筆查詢都存在唯一合法的最佳路徑。
輸出
每個地圖先輸出 Map #X(X 為地圖編號,從 1 開始),底下每筆查詢輸出 Query #Y、最佳路徑依序經過的站名(以空白分隔),以及 Each passenger has to pay : 金額 taka(金額四捨五入到小數點後兩位)。
解題思路
把邊權設計成「2 × 道路距離(油錢)+ 到達下一站要付的過路費」,再對每個會被查詢到的起點各自做一次 Dijkstra(起點的初始距離設為該站自己的過路費),這樣求出的最短距離就剛好是「從起點出發、沿途累積的總成本」。為了避免同一個起點重複計算,用 map 快取每個起點算過的最短距離與 prev 陣列;查詢時依 prev 陣列從終點往回推出完整路徑並反轉輸出,車資則是 1.1 × 總成本 ÷ 座位數。另外用一個 map 把車站名稱轉成整數編號,方便用陣列與 Dijkstra 處理。
程式碼
//author: Piau #include <bits/stdc++.h> using namespace std; #define pb push_back #define INF LONG_LONG_MAX/1000 #define WA() cin.tie(0)->sync_with_stdio(0) #define all(x) (x).begin(), (x).end() #define int long long #define PII pair<int, int> map<string, int> mp; vector<string> name; int id; int gid(string s) { if (mp.count(s)) return mp[s]; name.pb(s); return mp[s] = id++; } signed main() { WA(); int t = 1, T; for (cin >> T; t <= T; t++) { cout << (t-1 ? "\n" : "") << "Map #" << t << '\n'; mp.clear(); id = 0; name.clear(); int n; cin >> n; vector<vector<PII>> v(n); vector<int> p(n); for (auto &i : p) { string s; int k; cin >> s >> k; p[gid(s)] = k; } int m; for (cin >> m; m--;) { string a, b; int k; cin >> a >> b >> k; int na = gid(a), nb = gid(b); v[na].pb({nb, k}); v[nb].pb({na, k}); } map<int, vector<int>> mp, path; int q = 1, qq; for (cin >> qq; q <= qq; q++) { cout << "Query #" << q << '\n'; string a, b; int k; cin >> a >> b >> k; int na = gid(a), nb = gid(b); if (!mp.count(na)) { vector<int> &dis = mp[na], &prev = path[na]; dis.assign(n, INF); prev.assign(n, -1); priority_queue<PII, vector<PII>, greater<PII>> pq; pq.push({p[na], na}); dis[na] = p[na]; while (pq.size()) { int nd, n; tie(nd, n) = pq.top(); pq.pop(); if (nd > dis[n]) continue; for (auto &i : v[n]) { int tod, to; tie(to, tod) = i; if (dis[n] + 2*tod + p[to] < dis[to]) { pq.push({dis[to] = dis[n]+2*tod+p[to], to}); prev[to] = n; } } } } vector<int> g; for (int i = nb; i != na; i = path[na][i]) g.pb(i); g.pb(na); reverse(all(g)); for (auto &i : g) cout << name[i] << " \n"[&i == &g.back()]; cout << "Each passenger has to pay : " << fixed << setprecision(2) << 1.1*mp[na][nb]/k << " taka\n"; } } }