题目链接: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; }