Yurchiu's Blog

P1541 [NOIP2010 提高组] 乌龟棋

Yurchiu 2021-05-03, 07:18:46 857 隐藏左右两栏 展示左右两栏

链接:P1541 [NOIP2010 提高组] 乌龟棋

题意

乌龟棋的棋盘是一行 NN 个格子,每个格子上一个分数 aia_i(非负整数)。棋盘第 11 格是唯一的起点,第 NN 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。

乌龟棋中 MM 张爬行卡片,分成 44 种不同的类型(MM 张卡片中不一定包含所有 44 种类型的卡片,设第 ii 种卡片共 mim_i 张),每种类型的卡片上分别标有 11223344 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。

游戏中,乌龟棋子自动获得起点格子的分数,并且在后续的爬行中每到达一个格子,就得到该格子相应的分数。玩家最终游戏得分就是乌龟棋子从起点到终点过程中到过的所有格子的分数总和。

很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同。现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,求最多能得到多少分。

数据范围

1n3501\le n\le350M120M\le120mi40m_i\le400ai1000\le a_i\le100

点击查看题解

题解

使用 DP 求解。无后效性分析:只能前进,无法后退,也就没有环路。

首先我们可以设 f(i,j,k,l,n)f(i,j,k,l,n) 表示用掉操作的状态有 iijjkkll,到达 nn 点后的所能取得的最大分数(前 44 维分别表示用掉的 44 种操作的数目,后一维表示已经到达的点)。

之后,发现后一维可以用前四维求得,且五维数组爆空间,于是将最后一维降掉。

于是设 f(i,j,k,l)f(i,j,k,l) 表示用掉操作的状态有 iijjkkll 后的所能取得的最大分数。可推得状态转移方程:

f(now)=max{f(pre)+anow}f(\texttt{now})=\max\{f(\texttt{pre})+a_\texttt{now}\}

其中,now\texttt{now} 指当前状态,pre\texttt{pre} 指比当前状态少一个操作的状态。

代码

#include<bits/stdc++.h>
using namespace std;
namespace _yz
{
	const int N=400,M=40+5;
	int f[M][M][M][M],n,m,a[N],b[N];
	void yzmain()
	{
		int tmp;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) scanf("%d",a+i);
		for(int i=1;i<=m;i++)
			scanf("%d",&tmp),
			b[tmp]++;
		for(int i=0;i<=b[1];i++)
		 for(int j=0;j<=b[2];j++)
		  for(int k=0;k<=b[3];k++)
		   for(int l=0;l<=b[4];l++)
		   {
			tmp=0;
			if(i>=1) tmp=max(tmp,f[i-1][j][k][l]);
			if(j>=1) tmp=max(tmp,f[i][j-1][k][l]);
			if(k>=1) tmp=max(tmp,f[i][j][k-1][l]);
			if(l>=1) tmp=max(tmp,f[i][j][k][l-1]);
			f[i][j][k][l]=tmp+a[1+i*1+j*2+k*3+l*4];
		   }
		printf("%d\n",f[b[1]][b[2]][b[3]][b[4]]);
		return;
	}
}
int main()
{
	_yz::yzmain();
	return 0;
}




本文作者:Yurchiu

本文链接:https://yz-hs.github.io/3f632052a0ae/

版权声明:本博客中所有原创文章除特别声明外,均允许规范转载,转载请注明出处。所有非原创文章,按照原作者要求转载。


By Yurchiu.
其他物件杂物收纳
Hitokoto

Yurchiu 说,除了她以外的人都很强!嘤嘤嘤~~
博客信息
文章数目
158
最近更新
08-21
本站字数
350.6k
文章目录