AOJ 2200 Mr. Rito Post Office (Floyd预处理、dp)

快递到了:你是某个岛国(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的时候表示终止。

Sample Input

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

Output for the Sample Input

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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值