喵哈哈村的挑衅

来源:互联网 发布:自学网下载软件 编辑:程序博客网 时间:2024/04/27 16:05

题目大意:有两排物品,每排都有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;}
0 0