Light OJ 1031 - Easy Game(区间DP)

题目大意:
给你一个n,代表n个数字,现在有两个选手,选手A,B轮流有有一次机会,每个选手一次可以得到一个或者多个数字,从左侧或者右侧,但是不能同时从两边取数字,当所有的数字被取完,那么游戏结束。然后计算每个选手所得到数字的总和,每个选手都尽量让自己的分数比较多,选手A先开始取数。假设每个选手取得数字都是最优的,问A最多比B多多少分数,、
题目分析:
记忆化搜索,区间DP。
dp[该谁取了][左区间L][右区间] = 所能取到的最大值。
做下简单的预处理,得到区间L-R之间的和。
然后状态转移 dp[cur][L][R] = max(dp[cur][L][R], sum[L][K] + sum[K+1][R] - dp[cur^1][L][K] );
然后再反过来做一次DP, 总体求最大就行了。
 
=====================================================================================================
 
 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
const int INF = 1e9+7;
const int MAXN = 255;
int a[MAXN], dp[2][MAXN][MAXN];
int sum[MAXN];
int DFS(int cur,int L,int R)
{
    if( dp[cur][L][R] != -INF )
        return dp[cur][L][R];
    if(L > R)
        return 0;
    if(L == R)
        return dp[cur][L][R] = a[L];


    for(int i=L; i<=R; i++)
    {
        int A = sum[i]-sum[L-1];///所选取的区间
        int B = sum[R]-sum[i];///丢弃的区间总和
        dp[cur][L][R] = max(dp[cur][L][R],A + B - DFS(cur^1,i+1,R) );
    }
    for(int i=R; i>=L; i--)
    {
        int A = sum[R] - sum[i-1];
        int B = sum[i-1] - sum[L-1];
        dp[cur][L][R] = max(dp[cur][L][R],A + B - DFS(cur^1,L,i-1));
    }
    return dp[cur][L][R];
}

int main()
{
    int T, cas = 1, n;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d", &n);
        memset(sum, 0, sizeof(sum));

        for(int i=0; i<=n; i++)
        for(int j=0; j<=n; j++)
        dp[0][i][j] = dp[1][i][j] = -INF;

        for(int i=1; i<=n; i++)
        {
            scanf("%d", &a[i]);
            sum[i] = sum[i-1] + a[i];
        }
        int ans = DFS(0, 1, n);
        printf("Case %d: %d\n", cas++, 2*ans - sum[n]);
    }

    return 0;
}
/*

3

3
1 2 3
*/

 

posted @ 2015-10-26 16:30  向前走丶不回首  阅读(171)  评论(0编辑  收藏  举报