题目大意:给定两堆均含有n张牌的牌堆,牌上的数字分别是a[i],b[i],每次都已从任意一堆的顶部或底部拿一张,每个人都用最优策略,求先手能拿到的最大数字和?
设dp[i][j][k][l]表示先手从a数组区间[i,j]中以及b数组区间[k,l]中能选得的最大数字和
则dp[i][j][k][l]可由四个状态转移而来:
①先手拿a[i],由dp[i+1][j][k][l]转移而来,即 a[i]+sum(i+1,j,k,l)-dp[i+1][j][k][l];
②先手拿a[j],由dp[i][j-1][k][l]转移而来,即 a[j]+sum(i,j-1,k,l)-dp[i][j-1][k][l];
③先手拿b[k],由dp[i][j][k+1][l]转移而来,即 b[k]+sum(i,j,k+1,l)-dp[i][j][k+1][l];
④先手拿b[l],由dp[i][j][k][l-1]转移而来,即 b[l]+sum(i,j,k,l-1)-dp[i][j][k][l-1];
则dp[i][j][k][l]为上述最大值
感觉和只有一堆牌的情况差不多,但是连状态如何转移都知道了,却不知道如何实现,因为存在一堆没有选,而另一堆已选了的状态(这些状态没法表示,不好控制边界),看了题解才知道要用dfs控制边界从而进行状态的转移
#include
#include
#include
using namespace std;
const int MAXN=10005;
int par[MAXN],ps,pe,n,m,a[25],b[25];
int dp[25][25][25][25];//dp[i][j][k][l]表示先手从a数组区间[i,j]中以及b数组区间[k,l]中能选得的最大数字和
int dfs(int i,int j,int k,int l) {
if(i>j&&k>l) {
return 0;
}
if(dp[i][j][k][l]!=0) {
return dp[i][j][k][l];
}
int mx=0,sum=0;
if(i<=j) {
sum+=a[j]-a[i-1];
}
if(k<=l) {
sum+=b[l]-b[k-1];
}
if(i<=j) {
mx=max(mx,sum-dfs(i+1,j,k,l));
mx=max(mx,sum-dfs(i,j-1,k,l));
}
if(k<=l) {
mx=max(mx,sum-dfs(i,j,k+1,l));
mx=max(mx,sum-dfs(i,j,k,l-1));
}
return dp[i][j][k][l]=mx;
}
int main(){
int T;
scanf("%d",&T);
while(T-->0) {
a[0]=b[0]=0;
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(int i=1;i<=n;++i) {
scanf("%d",a+i);
a[i]+=a[i-1];
}
for(int i=1;i<=n;++i) {
scanf("%d",b+i);
b[i]+=b[i-1];
}
printf("%d\n",dfs(1,n,1,n));
}
return 0;
}