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;
}
标签:分数,int,卡牌,P1541,乌龟,数量
From: https://www.cnblogs.com/zxr000/p/17003936.html