HDU 4597 Play Game(区间DP(记忆化搜索))
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4597
题目大意:
有两行卡片,每个卡片都有各自的权值。
两个人轮流取卡片,每次只能从任一行的左端或右端取卡片。
假设两人都足够聪明,求先手能够取到的最大权值之和。
解题思路:
这题就归为区间DP吧,设dp[l1][r1][l2][r2]表示取完第一行[l1,r1]和第二行[l2,r2]的卡片时,先手能够获得的最大权值。
那么跟(l1,r1,l2,r2)关联的区间只有四个:
(l1+1,r1,l2,r2)
(l1,r1-1,l2,r2)
(l1,r1,l2+1,r2)
(l1,r1,l2,r2-1)
那么状态转移方程就为:
dp[l1][r1][l2][r2]=max(dp[l1][r1][l2][r2],sum-solve(l1+1,r1,l2,r2)),(l1<=r1)
dp[l1][r1][l2][r2]=max(dp[l1][r1][l2][r2],sum-solve(l1,r1-1,l2,r2)),(l1<=r1)
dp[l1][r1][l2][r2]=max(dp[l1][r1][l2][r2],sum-solve(l1,r1,l2+1,r2)),(l2<=r2)
dp[l1][r1][l2][r2]=max(dp[l1][r1][l2][r2],sum-solve(l1,r1,l2,r2-1)),(l2<=r2)
其中sum为第一行[l1,r1]和第二行[l2,r2]卡片权值之和,
从子区间推过来相当于先后手顺序发生了改变,所以sum-子区间最优解相当于取反,就是原来先手的操作变成后手,后手变成先手。
那么我们为什么要从最优子区间解里推过来呢,那样不就变成了让后手有了较优解了吗,不就让先手获得的权值变少了吗?因为题目说了两人足够聪明,选取的都是最优解。
代码:
1 #include<cstdio> 2 #include<cmath> 3 #include<cctype> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<set> 10 #include<map> 11 #include<stack> 12 #include<string> 13 #define lc(a) (a<<1) 14 #define rc(a) (a<<1|1) 15 #define MID(a,b) ((a+b)>>1) 16 #define fin(name) freopen(name,"r1",stdin) 17 #define fout(name) freopen(name,"w",stdout) 18 #define clr(arr,val) memset(arr,val,sizeof(arr)) 19 #define _for(i,start,end) for(int i=start;i<=end;i++) 20 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); 21 using namespace std; 22 typedef long long LL; 23 const int N=25; 24 const int INF=0x3f3f3f3f; 25 const double eps=1e-10; 26 27 int a[N],b[N]; 28 int dp[N][N][N][N]; 29 30 int solve(int l1,int r1,int l2,int r2){ 31 if(dp[l1][r1][l2][r2]!=-1) 32 return dp[l1][r1][l2][r2]; 33 34 int ans=0,sum=0; 35 if(l1<=r1) 36 sum+=a[r1]-a[l1-1]; 37 if(l2<=r2) 38 sum+=b[r2]-b[l2-1]; 39 //从子区间推过来相当于先后手顺序发生了改变,所以用减相当于取反 40 if(l1<=r1){ 41 ans=max(ans,sum-solve(l1+1,r1,l2,r2)); 42 ans=max(ans,sum-solve(l1,r1-1,l2,r2)); 43 } 44 if(l2<=r2){ 45 ans=max(ans,sum-solve(l1,r1,l2+1,r2)); 46 ans=max(ans,sum-solve(l1,r1,l2,r2-1)); 47 } 48 49 return dp[l1][r1][l2][r2]=ans; 50 } 51 52 int main(){ 53 FAST_IO; 54 int t; 55 scanf("%d",&t); 56 while(t--){ 57 memset(dp,-1,sizeof(dp)); 58 int n; 59 scanf("%d",&n); 60 _for(i,1,n){ 61 cin>>a[i]; 62 a[i]+=a[i-1]; 63 } 64 _for(i,1,n){ 65 cin>>b[i]; 66 b[i]+=b[i-1]; 67 } 68 printf("%d ",solve(1,n,1,n)); 69 } 70 return 0; 71 }