取数游戏(博弈+动规)

题目链接:https://nanti.jisuanke.com/t/48

题目描述

有如下一个双人游戏:N个正整数的序列放在一个游戏平台上,两人轮流从序列的两端取数,每次有数字被一个玩家取走后,这个数字被从序列中去掉并累加到取走该数的玩家的得分中,当数取尽时,游戏结束。以最终得分多者为胜。

编一个执行最优策略的程序,最优策略就是使自己能得到在当前情况下最大的可能的总分的策略。你的程序要始终为两位玩家执行最优策略。

输入第1行包括一个正整数N(2≤N≤100), 表示序列中正整数的个数。输入第2行包含用空格分隔的N个正整数(1≤所有正整数≤200)。

只有一行,用空格分隔的两个整数: 依次为先取数玩家和后取数玩家的最终得分。

样例输入复制

6 
4 7 2 9 5 2

样例输出复制

18 11

sum[i][j]表示从i位到j位所有的和,dp[i][j]表示从i位到j位使自身取到的所有值的最大和

想一下,先手要取掉两端中的一个值,此时无论先取者还是后取者都希望自己取的是最优的。

何为最优?

都保证自己会取得保证取完后总和相对大的,如何表示?

对于先手而言,

先取左边还是右边?当先手取完,就轮到后手去,后手一定会选择当前能令他得到最大分数的策略,其实当先手在[x, y]区间两端取走一个数,那么后手面临两个状态[x+1, y]和[x, y-1],先手想要取得最大值,一定会想让后手取这两种状态中的较小值,

即:dp[i][j]=sum[i][j]-min(dp[i+1][j],dp[i][j-1]),后半部分为后者所得和,前者所得和为总和减后者的和。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a[105],sum[105][105],dp[105][105];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        dp[i][i]=a[i];
        sum[i][i]=a[i];
    }
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++){
            sum[i][j]=sum[i][j-1]+a[j];
        }
    }
    for(int i=n-1;i>=0;i--){
        for(int j=i;j<n;j++){
            dp[i][j]=sum[i][j]-min(dp[i+1][j],dp[i][j-1]);
        }
    }
    printf("%d %d\n",dp[0][n-1],sum[0][n-1]-dp[0][n-1]);
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值