poj2385 动态规划

/*
	poj2385 2016.4.24 14:49
	题意:有两棵苹果树,t分钟其中一棵会掉一个苹果,一个人开始时站在树0下,可以在两棵苹果树间最多移动w次,求这个人最多可以吃到的苹果数量。
	题解:dp[t][w][x]表示第t分钟在苹果树x下,且已经最多移动了w次,注意是最多,不一定是刚好移动了w次。
	那么转移方程是
	对于当前第i分钟,掉的苹果在树val[i]:
	1. 当前第i分钟时,我刚好在val[i]树下,可以得到一个苹果。考虑其由来:
		1.1 i - 1分钟在val[i], 不需要移动。
			dp[i - 1][j][val[i]] + 1,还是j。
		1.2 i - 1分钟在1 - val[i]则需要移动一步,才能吃到该苹果。
			dp[i - 1][j - 1][1 - val[i]] + 1,消耗一步,前一分钟最多只能移动j - 1步。
	2. 当前第i分钟,我刚好在1 - val[i]树下,同样考虑其由来,则
		2.1 i - 1分钟在1 - val[i]下,不需要移动,继续等。
			dp[i - 1][j][1 - val[i]]
		2.2 i - 1分钟在val[i]下,需要移动一步,到树1 - val[i]
			dp[i - 1][j - 1][val[i]]
	上面两种情况都要考虑,即dp[i][j][0]和dp[i][j][1]
	例子:两分钟,最多只能走一步,且第一分钟是树0,然后是树1
	2, 1
	0 1
	考虑初始状态,即零分钟的情况:
	dp[0][0][0] = dp[0][1][0] = 0,可以,零分钟时在树0不移动,没有吃到苹果。
	dp[0][0][1] = dp[0][1][1] = -1,起始时在树0,不在树1,不合法。
	运算:
	1.1 
		1分钟最多走0步,在树0,且掉落的苹果在树0
	dp[1][0][0] = max(dp[0][0][0](0), dp[0][-1][1](越界不考虑,视为-1)) + 1 = 1
		在树1,没有掉苹果,不加一
	dp[1][0][1] = max(dp[0][0][1](-1,非法), dp[0][-1][0](-1)) = -1,同时非法(-1),则视为非法

	1.2 
		1分钟,最多走一步,在树1,相当于没走
	dp[1][1][0] = max(dp[0][1][0](0), dp[0][0][1](-1)) + 1 = 1
		从树0到树1,但在树0掉落...
	dp[1][1][1] = max(dp[0][1][1](-1), dp[0][0][0](0)) = 0

	2.1 
		2分钟,树1掉苹果。不走,在树0,相当于前2分钟都在树0,只等到一个苹果,不走...
	dp[2][0][0] = max(dp[1][0][0](1), dp[1][-1][1](-1)) = 1
		不走,然后在树1,是不可能的...
	dp[2][0][1] = max(dp[1][0][1](-1), dp[1][-1][0](-1)) + 1 = -1

	2.2 
		赖在树0不走
	dp[2][1][0] = max(dp[1][1][0](1), dp[1][0][1](-1)) = 1
		0分钟时移到树1一直等候,没吃到树0的苹果,吃到树1的苹果,或者1分钟在树0等候,然后2分钟移到树1等候,然后吃到两个苹果...
	dp[2][1][1] = max(dp[1][1][1](0), dp[1][0][0](1)) + 1 = 2
	结果就是max(dp[2][1][0], dp[2][1][1]) = 2
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MAX_T = 3000 + 10, MAX_W = 30 + 10;
int dp[MAX_T][MAX_W][2], val[MAX_T];
int main(){
	int t, w, i, j, k;
	//freopen("in.txt", "r", stdin);
	scanf("%d%d", &t, &w);
	for(i = 1; i <= t; i++){
		scanf("%d", &val[i]);
		val[i]--;
	}
	for(i = 0; i <= w; i++){
		dp[0][i][0] = 0;
		dp[0][i][1] = -1;
	}
	for(i = 1; i <= t; i++){
		for(j = 0; j <= w; j++){
			dp[i][j][val[i]] = -1;
			dp[i][j][1 - val[i]] = -1;
			if(dp[i - 1][j][val[i]] != -1){
				dp[i][j][val[i]] = max(dp[i][j][val[i]], dp[i - 1][j][val[i]] + 1);
			}
			if(j >= 1 && dp[i - 1][j - 1][1 - val[i]] != -1){
				dp[i][j][val[i]] = max(dp[i][j][val[i]], dp[i - 1][j - 1][1 - val[i]] + 1);
			}
			dp[i][j][1 - val[i]] = max(dp[i][j][1 - val[i]], dp[i - 1][j][1 - val[i]]);
			if(j >= 1){
				dp[i][j][1 - val[i]] = max(dp[i][j][1 - val[i]], dp[i - 1][j - 1][val[i]]);
			}
		}
	}
	printf("%d\n", max(dp[t][w][0], dp[t][w][1]));
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值