UVA 10891 Game of Sum 区间dp

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19461

题目意思大致是给你一串数字,A,B两个人轮流从两端取一段数字并得到该串数字的和的点数,每个人都尽可能的多的点数,问A最多能比B多多少点。

区间dp,一开始打算分AB,但是发现太麻烦了,最后用dp(l,r)表示在区间l~r中先手能赢的的最多点数。假设A是区间(l,r)的先手的话,如果A选择了(l,k )// 或(k+1,r)的数字,那他的得分(l,r)的总分减去B在余下区间作为先手能的到的分。
即dp(l,r) = min(sum - min(dp(l,k), dp(k+1,r)));
最终答案是A的得分减去B的得分 = 2*dp(1,n) - sum;
==>>预处理前缀和。

#include <cstring>
#include <iostream>
using namespace std;

int n;
int a[105];
int s[105];
int dp[105][105];

int DP(int l, int r) {
    if (dp[l][r] != -1) {
        return dp[l][r];
    }

    if (l == r) {
        return dp[l][r] = a[l];
    }

    int tmp = 0; 
    for (int k=l; k<r; k++) {
        tmp = min (tmp, DP(l, k));
        tmp = min (tmp, DP(k+1, r));
    }

    return dp[l][r] = s[r] - s[l-1] - tmp;
}

int main () {
    while (cin >> n) {
        if (n == 0) break;

        for (int i=1; i<=n; i++) {
            cin >> a[i];
        }
        memset(s, 0, sizeof s);
        for (int i=1; i<=n; i++) {
            s[i] = s[i-1] + a[i];
        }

        memset(dp, -1, sizeof dp);
        cout << 2 * DP(1, n) - s[n] << endl; 
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/xuelanghu/p/4564498.html