hdu4597 Play Game 区间DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4597

全国邀请赛通化赛区第8题--题目重现

思路:

区间DP的思想,想法是队友想出来的,感觉很秒,自己处理的边界,果断AC

边界处理很重要!!

对于两列牌。我们定义f[x][y][k][h]表示对于当前状态中第一列牌处于区间(i,j),第二列牌处于区间(k,h)时,先手(即当前要选择牌的选手)和后手之间的最大差值

定义sum1[x][y][k][h]表示先手的在此区间的获得的分数的最大值,sum2[x][y][k][h]表示后手在此区间的获得的分数的最大值

那么如果对于当前的区间,当前的选手选择y位置的牌,那么f[x][y][k][h]=(sum1[x][y-1][k][h]+a[y]-sum2[x][y-1][k][h]);

又很容易知道sum1[x][y-1][k][h]-sum2[x][y-1][k][h]=-f[x][y-1][k][h];

为什么是负的呢??很简单,因为上一次的先手是对方啊

同理,也可以选择x,k,h位置的牌

那么我们最终可以得到这样一个简单的DP转移方程

f[x][y][k][h]=max(-dfs(x,y-1,k,h)+a[y],-dfs(x+1,y,k,h)+a[x],-dfs(x,y,k+1,h)+b[k],-dfs(x,y,k,h-1)+b[h]);

状态方程有了,实现的时候最重要的就是边界处理了。

我用的是记忆化搜索的方式

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include<iostream>
 5 using namespace std;
 6 #define     N   22
 7 #define     INF 999999999
 8 int f[N][N][N][N], a[N], b[N], sum[2][N];
 9 bool vis[N][N][N][N];
10 int n;
11 int dfs(int i, int j, int k , int h)
12 {
13     int &x = f[i][j][k][h];
14     if(vis[i][j][k][h]) return x;
15     vis[i][j][k][h] = true;
16     x=-INF;
17     if(k==0&&h==0&&i==0&&j==0) return x=0;
18     else
19     if(k==0&&h==0 && i==j) return x=a[i];
20     else
21     if(i==0&&j==0 && k==h) return x=b[k];
22     else
23     if(k==0&&h==0) x=max(max(-dfs(i+1,j,0,0)+a[i],-dfs(i,j-1,0,0)+a[j]),x);
24     else
25     if(i==0&&j==0) x=max(max(-dfs(0,0,k+1,h)+b[k],-dfs(0,0,k,h-1)+b[h]),x);
26     else 
27     if(i==j && k!=h) x=max(max(max(-dfs(0,0,k,h)+a[i],-dfs(i,j,k+1,h)+b[k]),-dfs(i,j,k,h-1)+b[h]),x);
28     else
29     if(k==h && i!=j) x=max(max(max(-dfs(i,j,0,0)+b[k],-dfs(i+1,j,k,h)+a[i]),-dfs(i,j-1,k,h)+a[j]),x);
30     else
31     if(i==j&& k==h)  x=max(x,max(-dfs(0,0,k,h)+a[i],-dfs(i,j,0,0)+b[k]));
32     else
33     {   
34         x= max(x, max(-dfs(i, j-1, k, h) + a[j], -dfs(i+1, j, k, h) + a[i]));
35         x = max(x, max(-dfs(i, j, k, h-1) + b[h], -dfs(i, j, k+1, h) + b[k]));
36     }
37     
38     return x;
39 }
40 int main()
41 {
42     int cases;
43     scanf("%d", &cases);
44     while(cases--) {
45         scanf("%d", &n);
46         int sum=0;
47         for(int i = 1; i <= n; i++) scanf("%d", &a[i]),sum+=a[i];
48         for(int i = 1; i <= n; i++) scanf("%d", &b[i]),sum+=b[i];
49         memset(vis, false, sizeof(vis));
50         int res = dfs(1, n, 1, n);
51         cout<<(sum+res)/2<<endl;
52     }
53     return 0;
54 }
View Code

 

posted on 2013-08-24 17:43  GyyZyp  阅读(321)  评论(0编辑  收藏  举报

导航