题目链接: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]);
状态方程有了,实现的时候最重要的就是边界处理了。
我用的是记忆化搜索的方式
代码:
![](http://img.e-com-net.com/image/info8/b8d97b5613f94ed2ba791cad57d0b2ed.gif)
![](http://img.e-com-net.com/image/info8/2f88dd3f1cd145f59c0e47b51acdbd4b.gif)
1 #include2 #include <string.h> 3 #include 4 #include 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 }