动态规划——乌龟棋

题目描述

解题思路

首先这是一个很明显的线性dp的题目,很容易发现规律

数据输入

我们用 h[ N ] 数组存储每一个格子的分数

用 cnt [ ],数组表示每一中卡片的数目

1,状态表示

因为这里一个有4种跳跃方式可以选择

f[ i ][ a ][ b ][ c ][ d ]表示 走到第 i 个格子的时候,1,2,3,4四种跳跃卡片分别用了,a,b,c,d张。

但是其实我们是可以去掉一维的,因为我们可以根据 1,2,3,4卡片的使用情况来推算我们当前到的位置 i = a + 2 * b + 3 * c + 4 * d

所以我们的状态表示为

f[ a ][ b ][ c ][ d ]表示 走到第 i = a + 2 * b + 3 * c + 4 * d 个格子的时候,1,2,3,4四种跳跃卡片分别用了,a,b,c,d张。

2,状态转移方程

f[ a ][ b ][ c ][ d ]

=  max(f[ a - 1 ][ b ][ c ][ d ], f[ a ][ b - 1 ][ c ][ d ],f[ a ][ b ][ c - 1 ][ d ] ,f[ a ][ b ][ c ][ d - 1] ) + h[ j ]

3,初始化

根据题目信息  “游戏中,乌龟棋子自动获得起点格子的分数”

f[0][0][0][0] = h[0],因为价值大于等于 0 ,其他的格子都初始化为 0 即可。

4,填表顺序

咱们 4层for  从 a 到 d,从小到大即可

5,最终答案 

f[ cnt[ 1 ] ] [ cnt[ 2 ] ] [ cnt[ 3 ] ] [ cnt[ 4 ] ]

6,AC代码

#include <iostream>
using namespace std;

const int M = 45;
const int N = 360;

int h[N] = { 0 };
int f[M][M][M][M] = { 0 };
int cnt[5] = { 0 };

int n, m, sum;

int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++)
	{
		cin >> h[i];
	}
	for (int i = 1; i <= m; i++)
	{
		int x;
		cin >> x;
		cnt[x]++;
	}
	f[0][0][0][0] = h[0];

	for (int a = 0; a <= cnt[1]; a++)
	{
		for (int b = 0; b <= cnt[2]; b++)
		{
			for (int c = 0; c <= cnt[3]; c++)
			{
				for (int d = 0; d <= cnt[4]; d++)
				{
					int j = a + b * 2 + c * 3 + d * 4;
					if (a - 1 >= 0)
					{
						f[a][b][c][d] = max(f[a][b][c][d], f[a - 1][b][c][d] + h[j]);
					}
					if (b - 1 >= 0)
					{
						f[a][b][c][d] = max(f[a][b][c][d], f[a][b - 1][c][d] + h[j]);
					}
					if (c - 1 >= 0)
					{
						f[a][b][c][d] = max(f[a][b][c][d], f[a][b][c - 1][d] + h[j]);
					}
					if (d - 1 >= 0)
					{
						f[a][b][c][d] = max(f[a][b][c][d], f[a][b][c][d - 1] + h[j]);
					}
				}
			}
		}
	}

	cout << f[cnt[1]][cnt[2]][cnt[3]][cnt[4]] << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值