P1541 乌龟棋(动态规划)
题意
此处有n个位置,记为1~n,每个位置上都对应一个权值,乌龟从编号为1的位置出发,利用m张爬行卡片到达位置n,爬行卡牌有四种,分别可以让乌龟移动1,2,3,4步,并保证将m张牌全部用尽的时候,乌龟可以到达位置n,而乌龟每到达一个位置,就将获取这一位置的权值,问如何安排爬行卡牌的使用顺序,使得乌龟获得的总权值最大
解题思路
注意到乌龟用尽所有的爬行卡牌后将到达终点n,而且只能利用爬行卡牌从位置1开始移动,如果我们知道使用这张卡牌之前已经使用过每种卡牌多少个,那么每次使用任意一张爬行卡牌的时候,我们就很容易地找出转移方程,记dp[x1][x2][x3][x4]记录用了x1张步数为1的卡,x2张步数为2的卡,x3张步数为3的卡,x4张步数为4的卡的情况下获取的最大价值,同时也说明在位置 1 + x1 + 2 * x2 + 3 * x3 + 4 * x4 的最大价值是多少,那么转移方程为:
now = 1 + x1 + 2 * x2 + 3 * x3 + 4 * x4;
dp[x1][x2][x3][x4] = max(dp[x1][x2][x3][x4], dp[x1 - 1][x2][x3][x4] + val[now]);
dp[x1][x2][x3][x4] = max(dp[x1][x2][x3][x4], dp[x1][x2 - 1][x3][x4] + val[now]);
dp[x1][x2][x3][x4] = max(dp[x1][x2][x3][x4], dp[x1][x2][x3 - 1][x4] + val[now]);
dp[x1][x2][x3][x4] = max(dp[x1][x2][x3][x4], dp[x1][x2][x3][x4 - 1] + val[now]);
为了枚举dp数组的四个维度,我们先统计出四种爬行卡牌的总数,随后枚举四个维度,得到答案
代码区
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #include<fstream> #include<vector> #include<stack> #include <map> #include <iomanip> #define bug cout << "**********" << endl #define show(x, y) cout<<"["<<x<<","<<y<<"] " #define LOCAL = 1; using namespace std; typedef long long ll; const int inf = 1e9 + 7; const ll mod = 1e9 + 7; const int Max = 1e6 + 10; int n, m; int val[Max]; int num[5]; int dp[41][41][41][41]; //dp[x1][x2][x3][x4]记录用了x1张步数为1的卡,x2张步数为2的卡,x3张步数为3的卡,x4张步数为4的卡 int main() { #ifdef LOCAL // freopen("input.txt", "r", stdin); // freopen("output.txt", "w", stdout); #endif scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", val + i); for (int i = 1, x; i <= m; i++) scanf("%d", &x), num[x]++; dp[0][0][0][0] = val[1]; //初始情况,自动获取第一个位置的值 for (int x1 = 0; x1 <= num[1]; x1++) for (int x2 = 0; x2 <= num[2]; x2++) for (int x3 = 0; x3 <= num[3]; x3++) for (int x4 = 0; x4 <= num[4]; x4++) { int now = 1 + x1 + 2 * x2 + 3 * x3 + 4 * x4; //记录当前所在位置 if (x1 != 0) dp[x1][x2][x3][x4] = max(dp[x1][x2][x3][x4], dp[x1 - 1][x2][x3][x4] + val[now]); if (x2 != 0) dp[x1][x2][x3][x4] = max(dp[x1][x2][x3][x4], dp[x1][x2 - 1][x3][x4] + val[now]); if (x3 != 0) dp[x1][x2][x3][x4] = max(dp[x1][x2][x3][x4], dp[x1][x2][x3 - 1][x4] + val[now]); if (x4 != 0) dp[x1][x2][x3][x4] = max(dp[x1][x2][x3][x4], dp[x1][x2][x3][x4 - 1] + val[now]); } printf("%d\n", dp[num[1]][num[2]][num[3]][num[4]]); return 0; }