标签:
题目大意:有两排物品,每排都有n个,青君和狗哥轮流从每排的两侧拿任意一个物品。青君先手,假设狗哥绝顶聪明,青君所拿物品价值之和最大为多少?
分析:区间DP。
状态:dp[x1][y1][x2][y2],表示在区间[x1, y1]和区间[x2, y2]中能取到的最大值。
状态转移方程:有四种情况,分别为x1+1,y1-1,x2+1,y2-1。显然取四个中最小的那个。
下面的代码里,分别用a,b数组来表示两排的前缀和。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n, A[30], B[30];
int d[30][30][30][30], v[30][30][30][30];
int DP(int L1, int R1, int L2, int R2) {
if (v[L1][R1][L2][R2])
return d[L1][R1][L2][R2];
v[L1][R1][L2][R2] = 1;
int sum = 0, ans = 0;
if (L1 <= R1)
sum += A[R1] - A[L1-1];
if (L2 <= R2)
sum += B[R2] - B[L2-1];
if (L1 <= R1) {
ans = max(ans, sum - DP(L1+1, R1, L2, R2));
ans = max(ans, sum - DP(L1, R1-1, L2, R2));
}
if (L2 <= R2) {
ans = max(ans, sum - DP(L1, R1, L2+1, R2));
ans = max(ans, sum - DP(L1, R1, L2, R2-1));
}
return d[L1][R1][L2][R2] = ans;
}
int main() {
while (scanf("%d", &n) != EOF) {
memset(d, 0, sizeof(d));
memset(v, 0, sizeof(v));
for (int i = 1; i <= n; i++) {
int tmp;
scanf("%d", &tmp);
A[i] = A[i-1] + tmp;
}
for (int i = 1; i <= n; i++) {
int tmp;
scanf("%d", &tmp);
B[i] = B[i-1] + tmp;
}
printf("%d\n", DP(1, n, 1, n));
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/kl28978113/article/details/47112133