uva 10891 - Game of Sum(博弈,区间dp)

点击打开链接


题目大意:

有长度为n的正数序列,两个游戏者A 和B轮流取,A先取。每次玩家可以选择从序列左边或右边开始取一个或连续多个数字,问最终A最多可以比B大多少?


分析:

设f[l][r]表示对于区间[l,r]的序列,先取的人最多可以取的和。
那么,可以选择把[l,r]的所有数全部取光,或者只取一部分。
如果只取一部分,假设是[l,k]z这区间全部取,那么总共可以得到的和为sum[l,k]+(sum[k+1,r]-f[k+1][r])
所以状态转移为:
f[l][r] = sum[l][r]-min{ min{f[l][k], f[k+1][r]} }, l<=k<r




#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

typedef long long int64;
const int INF = 0x3f3f3f3f;

int n, arr[110], sum[110];
int f[110][110];

int main(){

    sum[0] = 0;
    while(~scanf("%d", &n) && n){
    
        for(int i=1; i<=n; ++i){
            scanf("%d", &arr[i]);
            sum[i] = sum[i-1] + arr[i];
        }

        memset(f, 0, sizeof(f));
        
        for(int i=1; i<=n; ++i)
            f[i][i] = arr[i];

        for(int len=2; len<=n; ++len){
            for(int l=1; l+len-1<=n; ++l){
                int r = l+len-1;
                
                int tot = sum[r] - sum[l-1];
                f[l][r] = tot;  // 把[l, r]全部取
                for(int k=l; k<r; ++k){
                    f[l][r] = max(f[l][r], tot-min(f[l][k], f[k+1][r])); //选择取[l,k]或[k+1,r]的情况
                }

            }
        }
        printf("%d\n", 2*f[1][n]-sum[n]);

    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值