洛谷P1541 乌龟棋(算法竞赛进阶指南,线性dp)

算法竞赛进阶指南,347页,线性dp

本题要点:
1、状态表示:
f[a][b][c][d]:表示你出了a张爬行牌1,b张爬行牌2,c张爬行牌3,d张爬行牌4时的得分
2、转态转移方程:
假设牌1, 牌2,牌3,牌4分别出现了 a, b, c, d次。
当前的坐标是x。 有x往回走1步,对应的最大得分是 f[a - 1][b][c][d],
同理, 有x往回走2步,对应的最大得分是 f[a][b - 1][c][d],
有x往回走3步,对应的最大得分是 f[a][b][c - 1][d],
有x往回走3步,对应的最大得分是 f[a][b][c][d - 1],
以上4个取一个最大值,和 score[x] 相加,就是 f[a][b][c][d] 的取值。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MaxN = 360;
int score[MaxN];
int card[5];	//a[1] 表示牌数等于1 的牌子个数
int f[41][41][41][41];
//f[a][b][c][d]:表示你出了a张爬行牌1,b张爬行牌2,c张爬行牌3,d张爬行牌4时的得分
int n, m;

void sovle()
{
	int x = 0;	//表示当前所在的坐标
	for(int a = 0; a <= card[1]; ++a)
	{
		for(int b = 0; b <= card[2]; ++b)
		{
			for(int c = 0; c <= card[3]; ++c)
			{
				for(int d = 0; d <= card[4]; ++d)
				{
					x = 1 + a + b * 2 + c * 3 + d * 4;				//算出当前所在的坐标
					f[a][b][c][d] = score[x];
					int pre = 0;	//向前走1,2, 3, 4 步得到的最大值
					if(a > 0)
						pre = max(pre, f[a - 1][b][c][d]);
					if(b > 0)
						pre = max(pre, f[a][b - 1][c][d]);	
					if(c > 0)
						pre = max(pre, f[a][b][c - 1][d]);	
					if(d > 0)
						pre = max(pre, f[a][b][c][d - 1]);	
					f[a][b][c][d] += pre;
				}
			}
		}
	}
	printf("%d\n", f[card[1]][card[2]][card[3]][card[4]]);
}

int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i)
	{
		scanf("%d", &score[i]);
	}
	int num;
	for(int i = 0; i < m; ++i)
	{
		scanf("%d", &num);
		card[num]++;
	}
	sovle();
	return 0;
}

/*
9 5
6 10 14 2 8 8 18 5 17
1 3 1 2 1
*/

/*
73
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值