uva 10891

来源:互联网 发布:php周末培训班 编辑:程序博客网 时间:2024/06/15 16:06

转自法力无边的厚白书。

题意:给出一个n个数的序列,两个人轮流从左端或右端开始取任意数。求第一人的数减去第二个人的最大值。

这一题,我们考虑从左边取还是从右边取,取多少个数。可以枚举每个状态。

dp[l[[r],表示从l到r,最大可以得到的数。它可以由dp[k][r], dp[l][m]得来,k = l  + 1---> r m = l ---- >r - 1。k和m相当于枚举取 1 -> n - 1个数的所有情况,也就是省下的数被取的情况,也就是另一个人取的最好情况。如果另一个人的最好情况大于0,那么就取完,如果小于0,那么就按照最优解的情况取。如何取完,需要m = 0。


#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int maxn = 100 + 5;int dp[maxn][maxn], num[maxn], sum[maxn];bool vis[maxn][maxn];int DP(int l, int r){    if(vis[l][r]) return dp[l][r];    vis[l][r] = 1;    int m = 0;//能使甚至取完所有数    for(int k = l + 1; k <= r; k++)        m = min(m, DP(k, r));    for(int k = l; k < r; k++)        m = min(m, DP(l, k));    dp[l][r] = sum[r] - sum[l - 1] - m;    //printf("%d %d %d\n", m, l, r);    return dp[l][r];}int main(){    int n;    sum[0] = 0;    while(scanf("%d", &n) == 1 && n)    {        //memset(dp, 0, sizeof(dp));        memset(vis, 0, sizeof(vis));        for(int i = 1; i <= n; i++)        {            scanf("%d", &num[i]);            sum[i] = sum[i - 1] + num[i];        }        printf("%d\n", 2 * DP(1, n) - sum[n]);//ans = DP(1, n) - ( sum[n] - DP(1, n) )    }    return 0;}