您的位置:首页 > 其它

Light OJ 1031 - Easy Game(区间DP)

2015-10-26 16:30 351 查看
题目大意:
给你一个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
);
}

return 0;
}
/*

3

3
1 2 3
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: