洛谷P1541 乌龟棋(dp)

题目链接:https://www.luogu.org/problemnew/show/P1541

Description:

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

乌龟棋中MMM张爬行卡片,分成4种不同的类型(MMM张卡片中不一定包含所有444种类型的卡片,见样例),每种类型的卡片上分别标有1,2,3,41,2,3,41,2,3,4四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。

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

很明显,用不同的爬行卡片使用顺序会使得最终游戏的得分不同,小明想要找到一种卡片使用顺序使得最终游戏得分最多。

现在,告诉你棋盘上每个格子的分数和所有的爬行卡片,你能告诉小明,他最多能得到多少分吗?

Input:

每行中两个数之间用一个空格隔开。

第111行222个正整数N,MN,MN,M,分别表示棋盘格子数和爬行卡片数。

第222行NNN个非负整数,a1,a2,…,aNa_1,a_2,…,a_Na1​,a2​,…,aN​,其中aia_iai​表示棋盘第iii个格子上的分数。

第333行MMM个整数,b1,b2,…,bMb_1,b_2,…,b_Mb1​,b2​,…,bM​,表示M张爬行卡片上的数字。

输入数据保证到达终点时刚好用光MMM张爬行卡片。

Output:

1个整数,表示小明最多能得到的分数。

Analysis:

这一题首先一点是,每类卡片的总量才是对结果有影响的。然后就不难写出状态转移方程。不过这里有一点是,需要内存优化。需要提的是,其实这种动归优化的区别就是,在原有的基础上上,改变的填表的位置,而其他的都是不变的。所以可以直接用(i-k+mod)%mod 这样的方式将位置i进行划分。只需要在填表和取结果时,套用这个变换式子就行,其他其实没有区别。

#define _CRT_SECURE_NO_WARNINGS  
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef  long long LL;
const int INF = 1 << 30;
const int maxn =355;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1);

int  n, m;
int dp[5][45][45][45],a[maxn],up[5];

int main()
{


	ios_base::sync_with_stdio(0);//用这个
	cin.tie(0);                    //就能防止cin超时orz
	
	while (cin >> n >> m) {
		_rep(i, 1, n) cin >> a[i];
		memset(up, 0, sizeof(up));
		memset(dp, 0, sizeof(dp));
		_rep(i, 1, m) {
			int x; cin >> x;
			up[x]++;
		}


		for (int i = 1; i <= n; ++i)
			for (int j1 = 0; j1 <= up[1]; ++j1)
				for (int j2 = 0; j2 <= up[2]; ++j2)
					_rep(j3, 0, up[3]) {
					int &ans = dp[i % 5][j1][j2][j3];
					if (i == 1) {
						dp[i%5][0][0][0] = a[1];
						continue;
					}
					if (i - 1 >= 1&&j1-1>=0) {
						int &ans1 = dp[(i - 1 + 5) % 5][j1-1][j2][j3];
						ans = max(ans, ans1+a[i]);
					}
					if (i - 2 >= 1&&j2-1>=0) {
						ans = max(ans, dp[(i - 2 + 5) % 5][j1][j2-1][j3]+a[i]);
					}
					if (i - 3 >= 1&&j3-1>=0) {
						ans = max(ans, dp[(i - 3 + 5) % 5][j1][j2][j3-1]+a[i]);
					}
					int j4 = i - j1 - j2 - j3 - 1;
					if (i - 4 >= 1&&j4-1>=0) {
						ans = max(ans, dp[(i - 4 + 5) % 5][j1][j2][j3]+a[i]);
					}

				}
		cout << dp[n%5][up[1]][up[2]][up[3]] << endl;
	}
	
	
	return 0;
}

 

你可能感兴趣的:(动态规划)