23 ACwing 312 乌龟棋 题解

乌龟棋

题面

乌龟棋的棋盘只有一行,该行有 N 个格子,每个格子上一个分数 \(a_i\)(非负整数)。

棋盘第 1 格是唯一的起点,第 N 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。

乌龟棋中共有 M 张爬行卡片,分成 4 种不同的类型(M 张卡片中不一定包含所有 4 种类型的卡片),每种类型的卡片上分别标有 1、2、3、4 四个数字之一的 \(b_i\) ,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数。

游戏中,玩家每次需要从所有的爬行卡片中选择一张之前没有使用过的爬行卡片,控制乌龟棋子前进相应的格子数,每张卡片只能使用一次。

\(1 \le N \le 350, \ 1 \le M \le 120\)

\(0 \le a_i \le 100, \ 1 \le b_i \le 4\)

每种卡片最多只有 40 张

题解

一个直接的想法是设 \(f(i,a,b,c,d)\) 表示到了第 \(i\) 个格子,用了 \(a\) 个 1 , \(b\) 个 2,\(c\) 个 3,\(d\) 个 4 ,所能获得的最大价值

但是最坏的空间复杂度为 \(O(N \times 40^4)\) ,约 \(3417.96875\ MB\) 爆炸,事件复杂度为 \(O(N \times 30^4)\) ,也很爆炸,所以我们要想办法优化

根据我们 “用最小维度覆盖所有状态空间” 的原则

发现 \(i\) 可以有后面的四个维度推出来,所以我们只需用 \(f(a, b, c, d)\) 即可覆盖所有状态空间

这样的时间复杂度为 \(O(30^4)\) ,空间复杂度为 \(O(40^4)\)

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

const int N = 360;

int n, m;
int cnt[5];
int val[N];
int f[42][42][42][42];

int main () {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++)
        cin >> val[i];
    for (int i = 1; i <= m; i ++) {
        int x;
        cin >> x;
        cnt[x] ++;
    }
    int A = cnt[1], B = cnt[2], C = cnt[3], D = cnt[4];
    for (int a = 0; a <= A; a ++) {
        for (int b = 0; b <= B; b ++) {
            for (int c = 0; c <= C; c ++) {
                for (int d = 0; d <= D; d ++) {
                    int &now = f[a][b][c][d];
                    if (a) now = max (now, f[a - 1][b][c][d]);
                    if (b) now = max (now, f[a][b - 1][c][d]);
                    if (c) now = max (now, f[a][b][c - 1][d]);
                    if (d) now = max (now, f[a][b][c][d - 1]);
                    int pos = a + b * 2 + c * 3 + d * 4 + 1;
                    now += val[pos];
                }
            }
        }
    }
    cout << f[A][B][C][D] << endl;

    return 0;
}
posted @ 2025-10-05 18:06  michaele  阅读(13)  评论(0)    收藏  举报