快递到了:你是某个岛国(ACM-ICPC Japan)上的一个苦逼程序员,你有一个当邮递员的好基友利腾桑遇到麻烦了:全岛有一些镇子通过水路和旱路相连,走水路必须要用船,在X处下船了船就停在X处。而且岛上只有一条船,下次想走水路还是得回到X处才行;两个镇子之间可能有两条以上的水路或旱路;邮递员必须按照清单上的镇子顺序送快递(镇子可能重复,并且对于重复的镇子不允许一次性处理,比如ABCB的话B一定要按顺序走两次才行)。
测试数据有多组:
N M
x1 y1 t1 sl1
x2 y2 t2 sl2
…
xM yM tM slM
R
z1 z2 … zR
N (2 ≤ N ≤ 200) 是镇子的数量,M (1 ≤ M ≤ 10000) 是旱路和水路合计的数量。从第2行到第M + 1行是路径的描述,路径连接xi yi两地,路径花费 ti (1 ≤ ti ≤ 1000)时间,sli 为L时表示是旱路,S时表示是水路。可能有两条及以上路径连接两个镇子,并且路径都是双向的。
M + 2行的R是利腾需要去的镇子的数量,M + 3是利腾需要去的镇子的编号。
初始状态利腾和船都在第一个镇子,且肯定有方法达到需要去的镇子。
测试数据为0 0的时候表示终止。
3 3 1 2 5 L 1 2 7 S 2 3 11 S 3 1 2 3 5 5 1 2 15 L 2 3 10 L 4 5 7 L 1 3 30 S 3 4 100 S 5 1 3 5 4 1 0 0
18 269
// 题目翻译来自 hankcs 的博客
Floyd 预处理 水路和陆路的两点最短距离
这题我没想出来 - - 我dp太弱
具体思路请看注释
AC代码如下:
// // AOJ 2200 Mr. Rito Post Office // // Created by TaoSama on 2015-03-20 // Copyright (c) 2015 TaoSama. All rights reserved. // #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> #define CLR(x,y) memset(x, y, sizeof(x)) using namespace std; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const int N = 1e5 + 10; int sea[205][205], land[205][205], dp[1005][205]; int n, m, r, a[1005]; int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(cin >> n >> m && (n + m)) { for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) sea[i][j] = land[i][j] = i == j ? 0 : INF; for(int i = 1; i <= m; ++i) { int x, y, t; char c; cin >> x >> y >> t >> c; if(c == 'S') sea[x][y] = sea[y][x] = min(sea[x][y], t); else land[x][y] = land[y][x] = min(land[x][y], t); } cin >> r; for(int i = 1; i <= r; ++i) cin >> a[i]; //Floyd for(int k = 1; k <= n; ++k) { for(int i = 1; i <= n; ++i) { for(int j = 1; j <= n; ++j) { sea[i][j] = min(sea[i][j], sea[i][k] + sea[k][j]); land[i][j] = min(land[i][j], land[i][k] + land[k][j]); } } } //dp[i][j]:= 到达i镇子 船停在j镇子的最小时间 memset(dp, 0x3f, sizeof dp); dp[1][a[1]] = 0; for(int i = 1; i <= r; ++i) { for(int j = 1; j <= n; ++j) { //一定可以走陆路 dp[i][j] = min(dp[i][j], dp[i - 1][j] + land[a[i - 1]][a[i]]); for(int k = 1; k <= n; ++k) //枚举水路船停的位置 //从i-1镇子回到船在的j 开船到k镇子船丢在那里 陆路从k到i镇子 //三个INF 可能加爆。。。。。 dp[i][k] = min((long long)dp[i][k], (long long)dp[i - 1][j] + land[a[i - 1]][j] + sea[j][k] + land[k][a[i]]); } } cout << *min_element(dp[r], dp[r] + n + 1) << endl; } return 0; }