NOIP 2010 乌龟棋 DP (COGS 519)

深知自己DP很弱,昨天被POJ上的一道DP题卡了一个晚上,而且是想不出来状态,写不出来方程的卡住。TAT
所以来写一道水一点的找找自信。哭

说水也不水,因为我一开始想的状态是f[i][c1][c2][c3][c4]表示在第i个格子,第i种卡牌剩ci张时所得的分数,状态转移就是f[i][c1][c2][c3][c4] = max(f[i-1][c1+1][c2][c3][c4], f[i-2][c1][c2+1][c3][c4]……)+s[i];不过很显然这个会爆内存。

不过我们可以想到,因为保证4种卡牌用完时是走到终点的,也就是说当前在哪个点,可以又四种卡牌剩余量推得,为了方便,可以改成ci表示第i种卡牌用了ci张。
那么状态转移就是f[c1][c2][c3][c4] = max(f[c1-1][c2][c3][c4], f[c1][c2-2][c3][c4], f[c1][c2][c3-1][c4], f[c1][c2][c3][c4-1])+s[1+c1+c2*2+c3*3+c4*4]. 边界f[0][0][0][0] = s[1].

#include <cstdio>
#include <algorithm>
using namespace std;

int n, m, s[355], f[45][45][45][45], t, c[5];

int main()
{
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++)
		scanf("%d", s+i);
	for(int i = 1; i <= m; i++){
		scanf("%d", &t);
		c[t]++;
	}
	
	f[0][0][0][0] = s[1];
	for(int c1 = 0; c1 <= c[1]; c1++)
	for(int c2 = 0; c2 <= c[2]; c2++)
	for(int c3 = 0; c3 <= c[3]; c3++)
	for(int c4 = 0; c4 <= c[4]; c4++){
		if(c1-1>=0)
			f[c1][c2][c3][c4] = max(
			f[c1-1][c2][c3][c4]+s[1+c1+c2*2+c3*3+c4*4],
			f[c1][c2][c3][c4]);
		if(c2-1>=0)
			f[c1][c2][c3][c4] = max(
			f[c1][c2-1][c3][c4]+s[1+c1+c2*2+c3*3+c4*4],
			f[c1][c2][c3][c4]);
		if(c3-1>=0)
			f[c1][c2][c3][c4] = max(
			f[c1][c2][c3-1][c4]+s[1+c1+c2*2+c3*3+c4*4],
			f[c1][c2][c3][c4]);
		if(c4-1>=0)
			f[c1][c2][c3][c4] = max(
			f[c1][c2][c3][c4-1]+s[1+c1+c2*2+c3*3+c4*4],
			f[c1][c2][c3][c4]);
	}	
	printf("%d", f[c[1]][c[2]][c[3]][c[4]]);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值