P1541 乌龟棋

P1541 乌龟棋

题意

一共有 \(N\) 个格子,每个格子上有一个分数,一共有四种卡牌: \(1,2,3,4\) ,使用一种卡牌之后,乌龟将前进对应的长度。每张卡牌只能使用一次,乌龟的起点为 \(1\) ,现在给出各个格子上的分数,以及卡牌的数量,保证乌龟用完所有卡牌之后刚好到达终点,求乌龟到达终点时获得的最大分数是多少?

思路:

到达一个点时,有四种操作,分别是选择四种卡牌中的一种,所以想到动态规划,最直接的状态定义为 \(f[i][a][b][c][d]\) 表示到达第 \(i\) 个点,第一种卡牌数量为 \(a\) ,第二种卡牌数量为 \(b\) ,第三种卡牌数量为 \(c\) ,第四种卡牌数量为 \(d\) 时,获得的最大分数。

但是根据数据范围分析时间复杂度可知,这样的状态定义会 MLE 并且会 TLE,所以就想还有哪里可以优化一下。这时候可以发现,当我们知道使用卡牌的情况的时候,其实我们就可以知道当前乌龟到达了哪个点,这样第一维度其实就没有任何意义。那么剩下后面四维的话,是满足题目时限的。

定义 \(f[a][b][c][d]\) : 第一种卡牌数量为 \(a\) ,第二种卡牌数量为 \(b\) ,第三种卡牌数量为 \(c\) ,第四种卡牌数量为 \(d\) 时,到终点可以获得的最大分数。

实现:

#include <bits/stdc++.h>
using namespace std;
const int N = 45, M = 255;
int a[M];
int f[N][N][N][N];
int b[5], c[5];

int dp(int b[])
{
    if (f[b[1]][b[2]][b[3]][b[4]])
        return f[b[1]][b[2]][b[3]][b[4]];

    int mmax = 0;
    for (int i = 1; i <= 4; i++)
    {
        if (b[i])
        {
            b[i]--;
            int to = 1;
            for (int j = 1; j <= 4; j++)
            {
                to += j * (c[j] - b[j]);
            }
            mmax = max(mmax, dp(b) + a[to]);
            b[i]++;
        }
    }
    return f[b[1]][b[2]][b[3]][b[4]] = mmax;
}

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);

    for (int i = 1; i <= m; i++)
    {
        int x;
        scanf("%d", &x);
        b[x]++;
        c[x]++;
    }

    printf("%d\n", dp(b) + a[1]);
    return 0;
}
posted @ 2022-12-25 13:34  zxr000  阅读(44)  评论(0编辑  收藏  举报