VUA-10891-Game of sum

                                    Game  of sum

题目大意:

给你一个串数字,每次只能选一边,然后取走一些数,你拿到的数字就是你的分数,求先手的人可以比后手的人最多多拿多少分


区间DP问题

难就难在两头都可以取,而且对面也不傻,采取的也是最优策略···

依旧按照DP的思想,大问题转化为小问题

首先要直接计算最大差多少分是非常难的

但是知道先手最大拿多少分,那么就可以计算出后手拿多少分(反正总分就这么多)

这样,由已知推未知,那么最大值就是上一步中最小值加上这一步的值

先手的人是a,后手的人是b

每次更新dp数组的时候,m表示的是把b的当成先手的,选最大值,然而a不会让他拿到最大值的,只会让他拿到最小情况中的最大值

整个过程需要倒着来看,因为DP就是由上个状态递推下个状态,那么对于选数,整个过程都是反着

总的来说,每次更新dp就是看成a的先手机会先存着,让b先先手,那么为了让b虽然先手,但是拿到最小的

那么就要找其中先手的最小值,这样,a的先手机会就用来把那些剩下的数全选了,这样保证了b拿到了最小值

依次递推

然后更新dp数组,最后得出结果

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int a[110],sum[110];
int dp[110][110];//dp[i][j]表示从i到j先手可以拿到的最大值
int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        memset(sum,0,sizeof(sum));
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        for(int i=1; i<=n; i++)//先初始化
        {
            dp[i][i]=a[i];
        }
        for(int l=2; l<=n; l++)
        {
            for(int i=1,j=l; j<=n; i++,j++)
            {
                int m,ans=-9999999;
                for(int k=i; k<j; k++)
                {
                    m=min(dp[i][k],dp[k+1][j]);//找出中间的最小值(m是后手拿到的分数)
                    m=sum[j]-sum[i-1]-m;//m表示上一笔选的值
                    if(m>ans)
                    {
                        ans=m;
                    }
                }
                if(sum[j]-sum[i-1]>ans)//如果一下选完可以最大值最大
                {
                    ans=sum[j]-sum[i-1];
                }
                dp[i][j]=ans;
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                printf("%d ",dp[i][j]);
            }
            printf("\n");
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值