洛谷,UVA1025,简单dp

lrj紫皮书268页

时间是单向流逝的,是一个天然的“序”。影响到决策的只有当前时间和所处的车站,所以可以用d(i,j)表示时刻i,你在车站j(编号为1~n),最少还需要等待多长时间。边界条件是d(T,n)=0,其他d(T,i)(i不等于n)为正无穷。有如下3种决策。
决策1:等1分钟。
决策2:搭乘往右开的车(如果有)。
决策3:搭乘往左开的车(如果有)。
在程序中定义一个数组has_train。has_train[t][i][0]表示时刻t,在车站i是否有往右开的火车,has_train[t][i][1]类似,不过记录的是往左开的火车。
状态有O(nT)个,每个状态最多只有3个决策,因此总时间复杂度为O(nT)。
——摘自《算法竞赛入门经典(第2版)》

AC代码
错误就是MAX一开始开成了50,导致RE;
因为没考虑到T的范围,误将T的范围也当成了N的范围

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int MAX = 220; // 这里一开始开成了50,太小了导致RE
const int INF = (1<<30);
int dp[MAX][MAX]; // dp[i][j] 表示i时刻j站点在T时刻到n所用的最少等待时间 
int has_train[MAX][MAX][2];//has_train[i][j][0] = true 表示i时刻j站点有向右的车可以乘坐 

int main()
{
	int n, T, t[MAX], M1, M2;
	int tot = 0; 
	for (;;) {
		tot++;
		// 初始化 dp 和 has_train数组 
		memset(dp, 0, sizeof(dp));
		memset(has_train, 0, sizeof(has_train));
		memset(t, 0, sizeof(t));
		// 读入数据,完成has_train 
		cin >> n;
		if (n == 0) break;
		cin >> T;
		// 只有 1~n-1 ,t[0] t[n] == 0 
		for (int i = 1; i < n; i++) {
			cin >> t[i];
		}
		// right
		cin >> M1;
		for (int k = 0; k < M1; k++) {
			int a;
			cin >> a;
			for (int i = 1; i <= n; i++) {
				has_train[a][i][0] = 1;
				a += t[i];
			}
		}
		// left
		cin >> M2;
		for (int k = 0; k < M2; k++) {
			int b;
			cin >> b;
			for (int i = n; i >= 1; i--) {
				has_train[b][i][1] = 1;
				b += t[i-1];
			}
		}
		
		// 开始动态规划处理
		// T时刻已到达n站,T[n][0] = 0; 其他车站不可到达 为INF 
		for (int i = 1; i < n; i++) dp[T][i] = INF; 
		dp[T][n] = 0; 
		// 递推
		for (int i = T - 1; i >= 0; i--) {
			// 这个for表示:在某个时间点i,更新各个站点的状态 
			for (int 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]); // right
					
				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]); // left 
				
				// 这三种情况枚举顺序执行完,dp[i][j] 就是这个状态下等待时间的最小值了 
			}
		}
		// 递归
		//slove(0, 1); 
		
		cout << "Case Number " << tot << ": ";
		if (dp[0][1] < INF)  cout << dp[0][1] << endl;
		else 				 cout << "impossible" << endl;
	} 
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值