有一个(1 imes n)的网格图,每个格子上有一个数字,有一只乌龟从第一个格子出发,现在有四种卡片,分别表示使用后向前走1,2,3,4步,有(a,b,c,d)张,每次可以任意选择一张卡片使用,保证用完卡片后到达第n个格子,到达的格子取走它的数字,问取走的数字之和的最大值,(1 ≤ N≤ 350,1 ≤M≤ 120),且4 种爬行卡片,每种卡片的张数不会
超过40。
解
不难想到设出表现走到的格子,和剩余的各种卡片的张数的递推方程,但事实上,确定了卡片张数,即确定了到达的格子,于是没必要保存,因此设(f[i][j][k][l])表示每种卡片各用了i,j,k,l张的取走的最大数字和,于是有
[f[i][j][k][l]=max{f[i-1][j][k][l],f[i][j-1][k][l],
]
[f[i][j][k-1][l],f[i][j][k][l-1]}
]
边界:(f[0][0][0][0]=0),其余无线小
答案:(f[a][b][c][d])
以下代码使用的是顺转移的方式。
参考代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
using namespace std;
int dp[41][41][41][41],
a[351],h[5];
il int max(int,int);
int main(){
int n,m,i,j,k,l;scanf("%d%d",&n,&m);
for(i=0;i<n;++i)scanf("%d",&a[i]);
while(m--)scanf("%d",&i),++h[i];
memset(dp,-1,sizeof(dp)),dp[0][0][0][0]=a[0];
for(i=0;i<=h[1];++i)
for(j=0;j<=h[2];++j)
for(k=0;k<=h[3];++k)
for(l=0;l<=h[4];++l){
if(dp[i][j][k][l]<0)continue;
dp[i+1][j][k][l]=max(dp[i+1][j][k][l],dp[i][j][k][l]+a[i+j*2+k*3+l*4+1]);
dp[i][j+1][k][l]=max(dp[i][j+1][k][l],dp[i][j][k][l]+a[i+j*2+k*3+l*4+2]);
dp[i][j][k+1][l]=max(dp[i][j][k+1][l],dp[i][j][k][l]+a[i+j*2+k*3+l*4+3]);
dp[i][j][k][l+1]=max(dp[i][j][k][l+1],dp[i][j][k][l]+a[i+j*2+k*3+l*4+4]);
}printf("%d",dp[h[1]][h[2]][h[3]][h[4]]);
return 0;
}
il int max(int a,int b){
return a>b?a:b;
}