HDU 4597 Play Game (记忆化搜索博弈DP)
题意
给出2*n个数,分两列放置,每列n个,现在alice和bob两个人依次从任意一列的对头或队尾哪一个数,alice先拿,且两个人都想拿最多,问alice最后能拿到数字总和的最大值是多少。思路
4月份通化邀请赛的题,当时竟然做不出来真是……记忆化搜索就OK了…… dp[a][b]{c}[d]=sum-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]); 其中dp[a][b]{c}[d]表示此状态下的最优情况,显然对方拿的越少自己就拿的越多,所以对于留给对手的4个状态应该让对方能拿的最大值最小,sum表示当前剩余的数字总和。然后直接搜索就行了。代码
[cpp] #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #include <set> #include <stack> #include <queue> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, end) for (int i = begin; i <= end; i ++) using namespace std; int dp[22][22][22][22]; int A[22], B[22]; int dfs(int a, int b, int c, int d, int sum){ if (~dp[a][b][c][d]) return dp[a][b][c][d]; if (a > b && c > d) return 0; int res = 0; if (a <= b){ res = max(res, sum - dfs(a+1, b, c, d, sum-A[a])); res = max(res, sum - dfs(a, b-1, c, d, sum-A[b])); } if (c <= d){ res = max(res, sum - dfs(a, b, c+1, d, sum-B[c])); res = max(res, sum - dfs(a, b, c, d-1, sum-B[d])); } return dp[a][b][c][d] = res; } int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); int t; scanf("%d", &t); while(t --){ int n, sum = 0; scanf("%d", &n); for (int i = 1; i <= n; i ++){ scanf("%d", &A[i]); sum += A[i]; } for (int i = 1; i <= n; i ++){ scanf("%d", &B[i]); sum += B[i]; } MEM(dp, -1); printf("%d\n", dfs(1, n, 1, n, sum)); } return 0; } [/cpp]举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG