2016BIT小学期——博弈DP(污神Alice和Bob)

1.题目描述:


Alice: 上课好无聊啊!!!

Bob:那你想干嘛?

Alice:我们来玩游戏好伐?

Bob:好哇!咋玩?

Alice:我们写n个正整数,然后轮流拿数字,每次可以拿任意多个,每次的得分是这次拿的数字中的最小值,我们俩每次拿数都要让自己的得分与对方的得分差值最大化,我俩试着拿一拿看看最后我比你高多少分吧~

Bob:我拒绝,这明明O(瞬间)就知道答案了为啥还要玩儿

Alice:哇你好厉害,那我写n个数你说按刚才的策略,我先拿,最后比你高多少分,你要是答对了我就嘻嘻嘻

Bob:好,你等着,嘿嘿嘿

输入

第一行输入一个整数T表示用例组数,每组用例第一行输入一个整数n表示要拿的正整数个数,之后输入n个正整数ai

输出

每组用例输出一个整数占一行,表示两人按游戏策略拿完所有数字后Alice比Bob高多少分

数据范围

1<=T<=10,1<=n<=50000,1<=ai<=10^9

样例输入

1

3

1 3 1

样例输出

2

样例解释

Alice拿3,Bob拿1 1,最后两者得分差值是3-1=2

 测试输入关于“测试输入”的帮助期待的输出关于“期待的输出”的帮助时间限制关于“时间限制”的帮助内存限制关于“内存限制”的帮助额外进程关于“{$a} 个额外进程”的帮助
测试用例 1以文本方式显示
  1. 1↵
  2. 3↵
  3. 1 3 1↵
以文本方式显示
  1. 2↵
1秒64M0

2.思路

题意:

两个人博弈,每次取任意多的数,但是每次取的数都只以当前取的最小的数来计分,每一轮取完之后记录该轮分差并计入总分,最后输出总分,但是每个人都想让自己与对方的分差是最大的(这句话其实是最有歧义也是最容易理解错的一句话)

下面我对上面那句最有歧义的话来进行以下分析

出题人其实是真的想通过这句话来给我们传达正确的意思,但是可能我们想问题的时候存在思维定式了

首先,注意,整个过程中实际上是不存在一轮一轮的概念的,我们每次都想要,也就是说,我们是不考虑之前的决策的

我们都是以当前为起点开始考虑取数来让自己与下一次对方取的时候的分差最大化

有的同学可能理解成当前A取完了,B想要让分差与A最小(这就是我们的思维定式和自以为是了)

实际上A取完了,我们B才不管上一次A取的是什么,B只关心为了下一次我能让下一次A取完之后与我的分差最大,我该怎么选

错误的想法:贪心

这种错误的想法是建立在我们之前说的自以为是的观点上(我在这上面WA了快10发了),我们每次都是取尽量大的元素为止,(我但是还专门找了两数之间分差最大的两个数的位置)然后我就只取最大的元素或者很多相同的最大的元素(当前有多个相同的最大元素)

但是我在测试用例的时候无意中发现一组用例出现了问题:

1 1 2 2 5 5 7 7 10 10

如果我们按照贪心的思想来做的话:答案应该是sum=10-7+5-2+1=7(这里我们就把题意理解错了)


接着上面的来讲

上面我们说了贪心的答案是7,我们贪心的取法是这样的

Alice->10,10

Bob->7,7

Alice->5,5

Bob->2,2

Alice->1,1

但是题意不是这样子的,题意的是我们每次只关心当前的决策

所以说,正确的理解思路下的选取方案应该是

Alice->10,10为了让下一次分差最大(10-7>7-5>=5-2)

Bob->7,7,5,5(计分只记5)为了让下一次分差最大(5-2>7-5)

Alice->2,2

Bob->1,1

正确的答案是sum=10-5+2-1=6

所以说,贪心的思路实在错误的理解了题目那句核心的话之下做出的错误的答案

很是揪心,我WA在这上面这么多次却浑然不知

正解思路:动态规划

孟义超大神的一句话点醒了我,本题的DP的递归性质

因为本题中我们每次所做的决策都无后效性,和最优子结构很相像,我在孟义超大神的指引下走上了DP这条正确的求解答道路上

首先,在这里,要想真的清楚的理解DP的性质,我们必须尽力抛开所谓的Alice和Bob两个只知道嘿嘿嘿的污神

我们这里只认一个叫做先手的人

还是拿刚才我们的例子来讲解

1 1 2 2 5 5 7 7 10 10

定义状态:

dp:这个叫做先手的人在取该位置上的元素可以造成的最大的分差(最终的结果)

状态转移方程:

dp[0]=0 根据定义显而易见

dp[i]=dp[i-1]>data[i]-dp[i-1]?dp[i-1]:data[i]-dp[i-1]

我知道大家肯定一眼都看不懂,我来解释一下

先明确,这里没有Alice也没有Bob,只有先手

当先手取完之后,肯定会造成分差,如果是Bob先取的话,那么Bob造成的分差肯定是正的,对Alice来说肯定是负的,同理,如果是Alice先取的话,那么Alice造成的分差肯定是正的,对Bob来说,这个分差肯定是负的

这么来说,比如现在先手取位置i,那么对于位置i-1来说,该先手肯定是后手,那么dp[i-1]对于这个当前取位置i的先手来说就是负的,我们的dp[i]的值很明显就是data[i]-dp[i-1](含义就是,我当前要把我之前的负逆差通过data[i]弥补回来)。

但是这样子就简简单单的求出来dp[i-1]了吗,并不是

假如说当前我计算出来的data[i]-dp[i-1]并没有dp[i-1]大,俺么这代表什么么意思呢

这样子代表的就是我们先手只取位置i的元素并不是最优的,我们可以通过先手取位置i和位置i-1(只以位置i-1的元素计分)元素获得更大的分差

实际上,思维敏感的同学很快就会发现,实际上,这意思就是,我们当前取位置i的先手转换到取位置i-1的先手上了

总之,对于这两种情况,我们取最大的一个

直到最后,我们求解出dp[n]时代表的含义就是先手取第n位置之后我们可以得到的最大的分差(就是最大的结果)

那么现在我们再来考虑Alice和Bob这两个污神,题中已经说了,Alice实现首,那么这个取位置n的先手就是Alice,我们直接输出dp[n]就好

 

最后,为了防止有的同学还不理解中间的步骤,我把上面的例子推导一遍

1 1 2 2 5 5 7 7 10 10

  1. dp[0]=0;
  2. dp[1]=max(data[1]-dp[0],dp[0])=max(1,0)=1;
  3. dp[2]=max(data[2]-dp[1],dp[1])=max(0,1)=1;
  4. dp[3]=max(data[3]-dp[2],dp[2])=max(1,1)=1;
  5. dp[4]=max(data[4]-dp[3],dp[3])=max(1,1)=1;
  6. dp[5]=max(data[5]-dp[4],dp[4])=max(4,1)=4;
  7. dp[6]=max(data[6]-dp[5],dp[5])=max(1,4)=4;这里的含义就是取6位置不如取5位置
  8. dp[7]=max(data[7]-dp[6],dp[6])=max(3,4)=4;这里的含义就是取7位置不如取5位置
  9. dp[8]=max(data[8]-dp[7],dp[7])=max(1,4)=4;这里的含义就是取8位置不如取7位置
  10. dp[9]=max(data[9]-dp[8],dp[8])=max(6,4)=6;
  11. dp[10]=max(data[10]-dp[9],dp[9])=max(4,6)=6;这里的含义就是取10位置不如取9位置

最后的dp数组是 0 1 1 1 1 4 4 4 4 6 6最大的取6,符合正确答案


3.AC代码:

只付上核心代码段:

for(int i=1;i<=n;i++)  
{  
      dp[i]=dp[i-1]>data[i]-dp[i-1]?dp[i-1]:data[i]-dp[i-1];  
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值