2 1 23 53 3 10 100 20 2 4 3
53 105
题目大意:给定两堆均含有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 <cstdio> #include <cstring> #include <algorithm> 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; }