题目链接:HDU 4597 Play Game
区间dp。
这题没做出来,看了题解说这是区间dp,貌似没做过这种题吧,这几天练练。
dp[x1][y1][x2][y2]表示在第一个堆只剩下x1到y1,第二个区间只剩下x2到y2最多可以取到的数的和。
那么当一个人面对这种状态时候,他有四种状态可以选择,分别是dp[x1 + 1][y1][x2][y2],dp[x1][y1 - 1][x2][y2],dp[x1][y1][x2 + 1][y2],dp[x1][y1][x2][y2 - 1],显然他应该选择这四个最小的那个。
两个sum数组分别表示两堆的前n项和。dp[x1][y1][x2][y2] = sum1[y1] - sum1[x1 -1] + sum2[y2] - sum2[x2 - 1] - min(dp[x1 + 1][y1][x2][y2],dp[x1][y1 - 1][x2][y2],dp[x1][y1][x2 + 1][y2],dp[x1][y1][x2][y2 - 1])),感觉这里挺难理解的。
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
const int MAX_N = 20 + 3;
int sum1[MAX_N], sum2[MAX_N];
int T, n;
int dp[MAX_N][MAX_N][MAX_N][MAX_N];
int dfs(int x1, int y1, int x2, int y2)
{
if(x1 > y1 && x2 > y2)
return 0;
int &ans = dp[x1][y1][x2][y2];
if(ans != -1)
return ans;
int sum = sum1[y1] - sum1[x1 -1] + sum2[y2] - sum2[x2 - 1];
if(x1 <= y1)
ans = max(ans, sum - min(dfs(x1 + 1, y1, x2, y2), dfs(x1, y1 - 1, x2, y2)));
if(x2 <= y2)
ans = max(ans, sum - min(dfs(x1, y1, x2 + 1, y2), dfs(x1, y1, x2, y2 - 1)));
return ans;
}
int main()
{
scanf("%d", &T);
while(T--)
{
memset(dp, -1, sizeof(dp));
scanf("%d", &n);
int temp = 0;
sum1[0] = sum2[0] = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &temp);
sum1[i] = sum1[i - 1] + temp;
}
for(int i = 1; i <= n; i++)
{
scanf("%d", &temp);
sum2[i] = sum2[i - 1] + temp;
}
printf("%d\n", dfs(1, n, 1, n));
}
return 0;
}