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