HDU 6199 gems gems gems DP动态规划 滚动数组

HDU 6199

还有一道题和这道差不多:codeforces 737  D 题解链接:https://blog.csdn.net/flyzer/article/details/90204019

题意:A和B两个人玩游戏,有一个数组a,两个人轮流取数,A先,两个人都是只能从左往右取,并且如果前一个人取了k个数,那么接下来的那个人就得取k或者k+1个数,如果剩下的数不足k个,那么游戏结束,输出  “A取出的值的和”  减去 “B取出的数的和” 的差。A想让这个差尽可能的大,B想让这个差尽可能的小,两个人都采取最优解,问最后的差是多少。

在一篇博客上看到一句话:

这种两人博弈一般都可以用两个dp写, 一个dp描述第一个人的最优态, 第二个dp描述第二个人的最优态,难点在于优化空间。

hdu 6199 和 cf 737 D 题目的区别在于,hdu这道题两个人都是从左往右取,而cf这道题是第一个人从左往右取,第二个人从右往左取,还有就是数据范围的差别,其他的完全一样。

cf那道题只要记忆化搜索就行了,但是hdu这道题不行,因为会MLE,所以只能动态规划,由于只跟后200个左右的状态有关,我们考虑用滚动数组的方式来储存dp。

hdu这道题推荐这篇博客:https://blog.csdn.net/V5ZSQ/article/details/79325575

AC code:

(因为是多组输入,不要忘了对dp数组进行初始化,否则会WA)

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
typedef long long ll;
#define Mod 233    //只要大于等于200就行
using namespace std;
int n,a[20001];
int dp[2001][255][2];
int sum[20001];
int main()
{
    int T;  scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        sum[0]=0;
        for(int i=1;i<=n;i++)
            {scanf("%d",&a[i]);sum[i]=sum[i-1]+a[i];}
        int ans=0;
        mem(dp,0);
        //从第i个石子开始取且上一轮对手取了j个
        for(int i=n;i>=1;i--)
            for(int j=200;j>=1;j--)
            {
                if(n-i+1<j)
                    continue;
                dp[i%Mod][j][0]=dp[(i+j)%Mod][j][1]+(sum[i+j-1]-sum[i-1]);
                dp[i%Mod][j][1]=dp[(i+j)%Mod][j][0]-(sum[i+j-1]-sum[i-1]);
                if(n-i+1>j)
                {
                    dp[i%Mod][j][0]=max(dp[i%Mod][j][0],dp[(i+j+1)%Mod][j+1][1]+(sum[i+j]-sum[i-1]));
                    dp[i%Mod][j][1]=min(dp[i%Mod][j][1],dp[(i+j+1)%Mod][j+1][0]-(sum[i+j]-sum[i-1]));
                }
            }
        printf("%d\n",dp[1][1][0]);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值