UVa 1025 A Spy in the Metro (dp)

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3466

题目理解:

有n(2 <= n <= 50)个车站,从左到右编号1-n, m1(1 <= m1 <= 50)辆车从1往右开, m2(1 <= m2 <= 50)辆车从n往左开。Mario时刻0从1出发,打算在T(0 <= T <= 200)时刻在n与人会面。在车站等车容易被抓,所以她尽量躲在火车上,让在车站等车的总时间尽量短。求在车站等车的最短时间

输入:

多组数据, 第一行n,第二行T,第三行n - 1个数t [1] - t [n - 1] (1 <= t <= 70)表示从第i个车站开到i + 1车站需要的时间(两个方向相同),第四行m1,第五行m1个整数表示各列车从1站的出发时间(0 <= d[i] <= 250) d[i] < d[i + 1]。第六行m2, 第七行各列车从n站出发的时间。不能到测输出impossible。

算法竞赛入门经典例题9-1

学dp总是感觉很迷茫,不知从何学起,还好难理解.... 多看,多理解,多想。

书上说,在每个车站有三种决策:
1、等一个时刻

2、乘往右开的列车(有的话)

3、乘往左开的列车(有的话)

程序中dp[ i ][ j ]表示时刻 i,在车站 j 到达目的要求需花费的最少时间。显然边界条件是dp[ T ][ n ] = 0。

方便起见,先打表has_train[ i ] [ j ] [ 0 ] 表示 i 时刻 在 j 车站有无向右开的车,has_train[ i ] [ j ] [ 1 ] 表示 i 时刻 在 j 车站有无向左开的车,打表的过程有一些小细节需要注意,祥见代码。 状态方程为dp[ i ][ j ] = min( dp[ i + 1][ j ] + 1, dp[ i + t[ j ]] [ j + 1 ], dp[i + t[j - 1]] [ j - 1] ) ,当然,后面两个是有车存在的情况下。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
const int inf = 0x3f3f3f3f;
int main() {
	int n, T, m1, m2, kase = 0;
	int t[55];
	int has_train[210][55][2];
	int dp[210][55];
	while(~scanf("%d", &n) && n) {
		scanf("%d", &T);
		int i, j;
		for(i = 1; i <= n - 1; i++) {
			scanf("%d", &t[i]);
		}
		memset(has_train, 0, sizeof(has_train));
		scanf("%d", &m1);
		int tmp;
		for(i = 1; i <= m1; i++) {  //打表记录有无向右开的车 
			scanf("%d", &tmp);
			for(j = 1; j <= n - 1; j++) {  //只需记录到 n - 1站,因为到了n站绝不会再往右开了 
				if(tmp < T) has_train[tmp][j][0] = 1;  // tmp == T的时候可看作无车,因为已经到时间了 
				tmp += t[j]; //开到下一站的时间 
			}
		}
		scanf("%d", &m2);
		for(i = 1; i <= m2; i++) {  //打表记录有无向左开的车 
			scanf("%d", &tmp);
			for(j = n; j >= 2; j--) {
				if(tmp < T) has_train[tmp][j][1] = 1; 
				tmp += t[j - 1];  //t[j - 1]也表示从 j 车站开到 j - 1车站的时间 
			}
		}
		for(i = 1; i <= n - 1; i++) dp[T][i] = inf; // 这些情况都是不可能到达的情况 
		dp[T][n] = 0; //边界情况 
		for(i = T - 1; i >= 0; i--) {  //从后往前递推 
			for(j = 1; j <= n; j++) {
				dp[i][j] = dp[i + 1][j] + 1;  //决策一 
				if(j < n && has_train[i][j][0] && i + t[j] <= T) 
					dp[i][j] = min(dp[i][j], dp[i + t[j]][j + 1]);  //决策二 ,上向右的车 
				if(j > 1 && has_train[i][j][1] && i + t[j - 1] <= T)
					dp[i][j] = min(dp[i][j], dp[i + t[j - 1]][j - 1]); //决策三 ,上向左的车 
			}
		}
		printf("Case Number %d: ", ++kase);
		if(dp[0][1] >= inf) printf("impossible\n");
		else printf("%d\n", dp[0][1]);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值