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\n",solve(1,n,1,n));
69     }
70     return 0;
71 }

猜你喜欢

转载自www.cnblogs.com/fu3638/p/8909708.html