原题链接:312. 乌龟棋 - AcWing题库
题意:给定一行中每点的权值,给定可选的4种前进方式,分别是 1,2,3,4,每种方式可选的数量有限,要求在用完前进方式时得到的总分最大
思路
只有一行,如果直接搜索的话,要遍历组合数级别的次数,每种前进方法在所有前进方法里找组合数 再相乘
复杂度太高
考虑到前面的选择实际上收到后面权重的影响,使用DP,只有一行,考虑线性DP
状态表示
一般需要记录当前走到哪个点,各种方式分别用了多少张,但是这么做的话空间会超 (用int数量 * int 字节 / 1024 / 1024)
当当前各种前进方法分别用了多少次已知,规模最大的n(当前走到哪里)就已知,可以去掉最大的一维
状态计算
分类,当使用了当前这些方法与其对应次数时,最后一个使用的方法是哪一个进行分类 取最大
实现
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 360, M = 45;
int n, m;
int f[M][M][M][M];
int a[N];
int cnt[5];
int main()
{
cin >> n >> m;
for(int i = 0; i < n; i ++)
cin >> a[i];
for(int i = 0; i < m; i ++)
{
int x;
cin >> x;
cnt[x] ++;
}
f[0][0][0][0] = a[0];
for(int A = 0; A <= cnt[1]; A ++)
for(int B = 0; B <= cnt[2]; B ++)
for(int C = 0; C <= cnt[3]; C ++)
for(int D = 0; D <= cnt[4]; D ++)
{
int w = a[1 * A + 2 * B + 3 * C + 4 * D];
int &v = f[A][B][C][D];
if(A) v = max(v, f[A-1][B][C][D] + w);
if(B) v = max(v, f[A][B-1][C][D] + w);
if(C) v = max(v, f[A][B][C-1][D] + w);
if(D) v = max(v, f[A][B][C][D-1] + w);
}
cout << f[cnt[1]][cnt[2]][cnt[3]][cnt[4]] << endl;
return 0;
}
十分简单的题,但是脑瘫之所以不会写在于不会算空间复杂度,见过的模型也少