题目: 传送门
思路:
显然是个dp题目,那么第一步就是状态的表示,一开始我想用 d p [ i ] [ j ] [ k ] [ l ] [ t ] dp[i][j][k][l][t] dp[i][j][k][l][t]表示当使用i张1,j张2, k张3,l张4后到达t所获取的最大分数,后来发现,一旦选取的4种牌的张数确定了,能到达的位置也就确定了,即到1+i+2j+3k+4l处(起点是1),那就用 d p [ i ] [ j ] [ k ] [ l ] dp[i][j][k][l] dp[i][j][k][l]表示 使用i张1,j张2, k张3,l张4到达1+i+2j+3k+4l处所获得的最大分数
状态转移方程为:
d p [ i ] [ j ] [ k ] [ l ] = a r r [ 1 + i + 2 ∗ j + 3 ∗ k + 4 ∗ l ] + m a x ( d p [ i − 1 ] [ j ] [ k ] [ l ] , d p [ i ] [ j − 1 ] [ k ] [ l ] , d p [ i ] [ j ] [ k − 1 ] [ l ] , d p [ i ] [ j ] [ k ] [ l − 1 ] ) dp[i][j][k][l]=arr[1+i+2*j+3*k+4*l] + max{(dp[i-1][j][k][l], dp[i][j-1][k][l], dp[i][j][k-1][l], dp[i][j][k][l-1])} dp[i][j][k][l]=arr[1+i+2∗j+3∗k+4∗l]+max(dp[i−1][j][k][l],dp[i][j−1][k][l],dp[i][j][k−1][l],dp[i][j][k][l−1])
Code:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <sstream>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1007;
typedef pair<int, int> P;
int dp[41][41][41][41];
int arr[4000];
int cnt[10];
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for (int i=1;i<=n;i++) {
scanf("%d",&arr[i]);
}
int x;
while (m--) {
scanf("%d", &x);
cnt[x]++;
}
dp[0][0][0][0] = arr[1];
for (int i=0;i<=cnt[1];i++) {
for (int j=0;j<=cnt[2];j++) {
for (int k=0;k<=cnt[3];k++) {
for (int l=0;l<=cnt[4];l++) {
int sum = -1;
int point = arr[1+i+2*j+3*k+4*l];//1是起点,在使用了i张1,j张2,k张3,l张4后,一定到了1+i+2*j+3*k+4*l处,后面要加上此处的分数
if (!i && !j && !k && !l) continue;
if (i) sum = max(sum, dp[i-1][j][k][l] + point);
if (j) sum = max(sum, dp[i][j-1][k][l] + point);
if (k) sum = max(sum, dp[i][j][k-1][l] + point);
if (l) sum = max(sum, dp[i][j][k][l-1] + point);
dp[i][j][k][l] = sum;
}
}
}
}
printf("%d\n", dp[cnt[1]][cnt[2]][cnt[3]][cnt[4]]);
return 0;
}