题意:个格子,每个格子有相应的分数,张卡牌,卡牌上的数字表示可以从当前格子往后走格,初始在一号格,自动得到一号格的分数,问选择卡牌进行走格子的方式中可获得的最大值为多少。
数据范围:,卡牌数字,每种卡牌数量为,保证
题解:
这种数据范围自然想到的是爆搜加剪枝。
由于最多有个状态,因为先使用一次号牌再使用一次号牌,与先使用一次号牌,再使用一次号牌是一种情况,如果重复递归的话复杂度爆炸,故想到记忆化搜索。 表示剩余号牌,号牌,号牌,号牌,当前在号格子走到号格子可得到的最大分数。每次记忆化一下即可。
代码:

#include<bits/stdc++.h>
using namespace std;

const int N = 50;
const int M = 360;
int f[N][N][N][N];
int n, m;
int cnt[5];
int v[N];
int score[M];

int dfs(int u, int a, int b, int c, int d) {
    if(u == n) return score[u];
    if(~f[a][b][c][d]) return f[a][b][c][d];

    int res = 0;
    if(cnt[1] > a) res = max(res, dfs(u + 1, a + 1, b, c, d));
    if(cnt[2] > b) res = max(res, dfs(u + 2, a, b + 1, c, d));
    if(cnt[3] > c) res = max(res, dfs(u + 3, a, b, c + 1, d));
    if(cnt[4] > d) res = max(res, dfs(u + 4, a, b, c, d + 1));
    return f[a][b][c][d] = score[u] + res;
} 

int main()
{
    memset(f, -1, sizeof f);
    memset(cnt, 0, sizeof cnt);
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &score[i]);
    for(int i = 1, x; i <= m; i++) {
        scanf("%d", &x); 
        cnt[x]++;
    }

    printf("%d\n", dfs(1, 0, 0, 0, 0));

    return 0;
}