算法题(202):乌龟棋
审题:
本题需要我们找到使用完所有卡片后小明所能得到的分数的最大值
思路:
方法一:动态规划由于本题也属于多阶段问题,故尝试动态规划
(1)状态表示:f[a][b][c][d]表示分别使用了abcd张值为1234的卡牌后到达i位置的最大分值
这里将i省略是因为i可以根据abcd求出
(2)状态转移方程:分为四类,是根据牌的值种类划分的
我们以最后一步来分析
通过最后一张牌走到i位置的方式总共有四种
假设是通过值为1的牌,那么我们i位置的分值就是i位置分值+使用了a-1张1,b张2,c张3,d张4的总分值,即如图所示
其他三类同理如图
(3)初始化:将f[0][0][0][0]初始化为x[1]
因为没使用牌走动的时候得到的分值就是起点的值
还有要注意状态转移方程中有类似a-1,b-1等数组访问,为了防止非法访问我们需要确保使用对应公式的时候a/b/c/d >= 1
(4)填表顺序:依次进行,从左到右
(5)输出答案:题目要求的是用完所有牌后的最大分值
解题:
#include<iostream> using namespace std; const int N = 360, M = 50; int n, m; int x[N], cnt[5]; int f[M][M][M][M];//表示分别使用了abcd张1234数值的牌后到达的位置收集到的最大分数int main() {//数据录入cin >> n >> m;for (int i = 1; i <= n; i++){cin >> x[i];}for (int i = 1; i <= m; i++){int t; cin >> t;cnt[t]++;}//初始化f[0][0][0][0] = x[1];for (int a = 0; a <= cnt[1]; a++)//1for (int b = 0; b <= cnt[2]; b++)//2for (int c = 0; c <= cnt[3]; c++)//3for (int d = 0; d <= cnt[4]; d++)//4{int i = 1 + a + 2 * b + 3 * c + 4 * d;int& t = f[a][b][c][d];if (a) t = max(t, f[a - 1][b][c][d] + x[i]);if (b) t = max(t, f[a][b-1][c][d] + x[i]);if (c) t = max(t, f[a][b][c-1][d] + x[i]);if (d) t = max(t, f[a][b][c][d-1] + x[i]);}//输出答案cout << f[cnt[1]][cnt[2]][cnt[3]][cnt[4]] << endl;return 0; }
这里使用的cnt数组来记录每一类卡牌的个数
P1541 [NOIP 2010 提高组] 乌龟棋 - 洛谷