专栏文章

题解:P1541 [NOIP2010 提高组] 乌龟棋

P1541题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqkmmhg
此快照首次捕获于
2025/12/04 06:21
3 个月前
此快照最后确认于
2025/12/04 06:21
3 个月前
查看原文

题目大意

nn 个格子,每个格子上都有一定的分数。再给 mm 张数值为 1144 的卡片,卡片上的数值代表前进的步数,每张卡片只能用一次。每到达一个格子就可以拿走该分数,问所有卡片用光时能够获得的最大分数。

解题思路

一眼动态规划,上动态规划六步分析法

一、定义问题状态

题目中共计四种卡片,每种卡片的数量与得分之间有联系,状态非常好设计。
f(a,b,c,d)f(a,b,c,d) 表示第 11 种卡片使用 aa 张,第 22 种卡片使用 bb 张,第 33 种卡片使用 cc 张,第 44 种卡片使用 dd 张时的最大分值。

二、分解子问题

分解子问题的目的是将问题拆分为相似的规模更小的问题,从而得到,子问题与原问题之间的状态转移方程。分解子问题时需要考虑,决策与约束条件。
f(a,b,c,d)=max{f(a1,b,c,d)+sc[step]a1f(a,b1,c,d)+sc[step]b1f(a,b,c1,d)+sc[step]c1f(a,b,c,d1)+sc[step]d1f(a,b,c,d)=\max\begin{cases}f(a-1,b,c,d) + sc[step] & a\ge 1\\ f(a,b-1,c,d) + sc[step] & b\ge 1\\ f(a,b,c-1,d) + sc[step] & c\ge 1\\f(a,b,c,d-1) + sc[step] & d\ge 1\end{cases}
其中 step=a+2×b+3×c+4×d+1 step=a+2\times b+3\times c+4\times d+1

三、初始化边界状态

边界状态即为不需要计算就能直接分析出的状态。这里是一张卡片都没有用时得分为在第 11 格处的分数。
f(0,0,0,0)=sc[1]f(0,0,0,0)=sc[1]

四、计算顺序

从小到大依次枚举卡片 1144 的张数。

五、最终答案

ans=f(cnt1,cnt2,cnt3,cnt4)ans=f(cnt1,cnt2,cnt3,cnt4)
其中 cnt1cnt1cnt4cnt4 表示第 11 至第 44 张卡片的总数量。

六、效率分析

时间复杂度和空间复杂度度都为 O(n4)O(n^4) 这里 nn 代表每种卡片的最大数量为 4040 没有超时和超空间。

代码实现

CPP
#include<bits/stdc++.h>
using namespace std;

const int maxn = 10005;
int n, m, a[maxn], b, cnt[5], f[52][52][52][52];

int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++)
		cin >> a[i];
	for(int i = 1; i <= m; i++){
		cin >> b;
		cnt[b]++;
	}
	f[0][0][0][0] = a[1];
	for(int i = 0; i <= cnt[1]; i++)
		for(int j = 0; j <= cnt[2]; j++)
			for(int k = 0; k <= cnt[3]; k++)
				for(int l = 0; l <= cnt[4]; l++){
					int step = i+2*j+3*k+4*l+1;
					if(i) f[i][j][k][l] = max(f[i][j][k][l], f[i-1][j][k][l] + a[step]);
					if(j) f[i][j][k][l] = max(f[i][j][k][l], f[i][j-1][k][l] + a[step]);
					if(k) f[i][j][k][l] = max(f[i][j][k][l], f[i][j][k-1][l] + a[step]);
					if(l) f[i][j][k][l] = max(f[i][j][k][l], f[i][j][k][l-1] + a[step]);
				}
	cout << f[cnt[1]][cnt[2]][cnt[3]][cnt[4]];
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...