这题真无语,比赛时不会做,想了一场贪心算法,没想到是个区间DP,白刷了那么多DP!
比完赛回来,听说是个区间DP,终于把题A了,但代码写得很搓,也不太好理解。后来发现这题竟然是白书上的例题!!!真是哭了,比赛的时候我们还带着白书呢!
发现白书上记忆化搜索的写法很优雅,也比较好理解,就写一个吧。才50行的代码!
dp[a][b][c][d]表示区间【a,b】,【c,d】先手能取到的最大值。
dp[a][b][c][d]=S-min(dp[a+1][b][c][d],dp[a][b-1][c][d],dp[a][b][c+1][d],dp[a][b][c][d-1]) S是[a,b],[c,d]区间所有的数之和
用记忆化搜索来写可以解决当一堆数取完,另一堆数没取完的问题,递推不是很好处理。
/*
* H.cpp
*
* Created on: 2013-5-28
* Author: zy
*/
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int x[21], y[21], T, n, s1[21], s2[21];
int dp[22][22][22][22];
const int INF = 0x3f3f3f3f;
int dfs(int a, int b, int c, int d)
{
if (a > b && c > d)
return 0;
if (dp[a][b][c][d])
return dp[a][b][c][d];
int m = INF;
if (a <= b)
{
m = min(m, dfs(a + 1, b, c, d));
m = min(m, dfs(a, b - 1, c, d));
}
if (c <= d)
{
m = min(m, dfs(a, b, c + 1, d));
m = min(m, dfs(a, b, c, d - 1));
}
dp[a][b][c][d] = s1[b] - s1[a - 1] + s2[d] - s2[c - 1] - m;
return dp[a][b][c][d];
}
int main()
{
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
s1[0] = s2[0] = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d", &x[i]);
s1[i] = s1[i - 1] + x[i];
}
for (int i = 1; i <= n; i++)
{
scanf("%d", &y[i]);
s2[i] = s2[i - 1] + y[i];
}
memset(dp, 0, sizeof(dp));
printf("%d\n", dfs(1, n, 1, n));
}
return 0;
}