# 題目: UVa 10171 - Meeting Prof. Miguel
# 題目說明
給一個有 weight
的有向圖,圖中的道路有年齡限制
給 Y
與 M
的起始點,求 Y
與 M
要會合的最短路徑
INPUT:
每筆測資第一行輸入一個整數 N
,代表接下來有 N
行
接著輸入四個大寫字元 age
、 connect
、 u
、 v
,與一個整數 w
age = Y
代表只有年輕人能走的路、age = M
代表只有老人能走的路connect = U
為單向連通、connect = B
為雙向連通u
連接到v
的weight(cost)
為w
接下來有兩個大寫字元 y
與 m
,前者代表年輕人的起始點,後者代表老人的起始點
當 N
為 0
時結束程式
OUTPUT:
輸出 Y
與 M
會合的最短路徑與會合的點
如果無法會合,則輸出 You will never meet.
# 解題方法
定義兩個 vector< vector<int> >
,分別為 G[0]
與 G[1]
G[x][i][j]
代表從 i
到 j
的最短路徑
先將 G[x]
中所有元素設為 501
,相當於無限大 (題目限制範圍為 < 500
)
判斷 age
為年輕人 (tmp = 0) 或老人 (tmp = 1)
將 G[tmp][U][V]
設為 w
,若為雙向則將 G[tmp][V][U]
設為 w
記得將自己走到自己設為 0
對於所有 0 ~ 25
的 i
, G[tmp][i][i] = 0
接下來跑 Floyd-Warshall algorithm
(佛洛依德演算法)
轉移方程為: G[tmp][i][j] = min(G[tmp][i][j], G[tmp][i][k] + G[tmp][k][j])
最後判斷是否會合,與輸出匯合點
# 參考程式碼
#include <iostream> | |
#include <vector> | |
#include <climits> | |
using namespace std; | |
int main() | |
{ | |
// fast io | |
ios::sync_with_stdio(false); | |
cout.tie(nullptr); | |
cin.tie(nullptr); | |
int N, w, U, V, Y, M, tmp; | |
char age, connect, u, v, y, m; | |
vector< vector<int> > G[2]; | |
while (cin >> N, N) | |
{ | |
// init | |
G[0].assign(26, vector<int>()); | |
G[1].assign(26, vector<int>()); | |
for (int i = 0; i < 26; ++i) G[0][i].assign(26, 501), G[1][i].assign(26, 501); | |
int Max = 0; | |
int ans = 501; | |
// store data in target graph | |
for (int i = 0; i < N; ++i) | |
{ | |
cin >> age >> connect >> u >> v >> w; | |
U = u - 'A'; | |
V = v - 'A'; | |
if (age == 'Y') tmp = 0; | |
else tmp = 1; | |
G[tmp][U][V] = w; | |
if (connect == 'B') G[tmp][V][U] = w; | |
Max = max(Max, max(U, V)); | |
} | |
for (int i = 0; i < 26; ++i) G[0][i][i] = G[1][i][i] = 0; | |
// Floyd-Warshall algorithm | |
for (int k = 0; k <= Max; ++k) for (int i = 0; i <= Max; ++i) for (int j = 0; j <= Max; ++j) | |
{ | |
G[0][i][j] = min(G[0][i][j], G[0][i][k] + G[0][k][j]); | |
G[1][i][j] = min(G[1][i][j], G[1][i][k] + G[1][k][j]); | |
} | |
cin >> y >> m; | |
Y = y - 'A'; | |
M = m - 'A'; | |
for (int i = 0; i <= Max; ++i) ans = min(ans, G[0][Y][i] + G[1][M][i]); | |
if (ans == 501) cout << "You will never meet.\n"; | |
else | |
{ | |
cout << ans; | |
for (int i = 0; i <= Max; ++i) if (ans == G[0][Y][i] + G[1][M][i]) cout << " " << char(i + 'A'); | |
cout << "\n"; | |
} | |
} | |
return 0; | |
} |
# 參考資料
https://github.com/morris821028/UVa/blob/master/volume101/10171%20-%20Meeting%20Prof.%20Miguel.cpp