浅谈Nim博弈 附hdu 2176 取(m堆)石子游戏 ,hdu 1850 Being a Good Boy in Spring Festival
来源:互联网 发布:一键复制淘宝别人宝贝 编辑:程序博客网 时间:2024/06/06 01:37
浅谈Nim博弈
最近两天学的Nim博弈,一些心得拿出来给大家分享一下,也算是记录一下自己的学习心得方便今后复习。本人水平有限,如有错误或不妥的地方,还请各位大牛多多指教(^_^)
尼姆博弈模型一般是这样的:
有三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少,取一个,多者不限,最后取光者得胜。给你三堆石头中的石头数:a,b,c,怎么样判断先手胜还是后手胜。
分析:
1.证明:
首先我们先自己模拟两个简单的例子, 三堆石子的数目分别是(0,2,2),我们可以枚举发现无论怎么走,先手都会输,另外一种情况,三堆石子的数目分别是(1,2,3),依然是先手输,因为无论先手怎么走,后手都可以将局势变成(0,n,n)这种局势。
那么我们再将局势推广到(0,n,n)的情况,发现如果先手取两个不为0的堆中的任何一个堆中的任何数量的石子,后手都可以对另外一个堆采取相同的操作,使局势依旧保持在(0,n,n)的状态,一直保持这样,直到最后先手不得不将一个堆中的石子全部取玩,那么后手马上可以将另外一个堆中剩余的石子取光,所以还是先手必胜。
那么,也就是说我们现在知道有三个奇异局势,分别是(0,0,0),(1,2,3),(0,n,n),那这三个局势看起来似乎没有什么联系。
真的没有吗?当然不可能,经过计算之后我们会发现这对三个奇异局势(a,b,c)都有a ^ b ^ c = 0。
那么也就是说这可能是奇异局势的特征咯,到底是不是没关系,我们可以证明一下:
首先定义P-position和N-position,其中P代表Previous,N代表Next。简单的说,就是P是必败态,N是必胜态
更严谨的定义是:1.无法进行任何移动的局面(也就是terminal position)是P-position;2.可以移动到P-position的局面是N-position;3.所有移动都导致N-position的局面是P-position。
这里对以上几点定义做出一点解释:第一点,无法进行任何移动的局面当然是必败的;第二点,如果当前是必胜态,那么当然要保证自己走完这一步之后留给对手的是必败态,所以可以移动到P态的是N态;第三点,自己无论现在这一步怎么走,走完这一步之后,留给对手的都是必胜态,这种局势当然是必败态。
那么现在拿出我们上面的假设:任何奇异局势(a,b,c)都有a ^ b ^ c = 0。
要证明这个假设,我们需要证明三个命题
1.根据该假设,所有terminal position都是P-position。
证明:因为terminal position只有一个,就是都是0的情况,那么不管多少个0异或之后结果肯定还是0。
2.根据该假设,当前被判为N-position的局势一定存在某种合法的移动,使得局势转变为P-position。
证明:对于任意一个局势(a1,a2........an)如果a1 ^ a2 ^...... ^ an != 0,那么设k = a1 ^ a2 ^...... ^ an ,从a1到an中一定存在一个数ai,它的二进制表示在k的最高位上为1,不然的话k二进制最高位上的1怎么来的。那么我现在设 s = ai ^ k = a1 ^ a2 ^.......^ a(i-1) ^ a(i+1) ^ .......an,则此时s二进制表示的最高位一定为0。(因为s ^ ai的最高位为1)所以, ai ^ k < ai成立,所以我们设ai ' = ai ^ k,则此时a1^a2^...^ai ' ^...^an = ai ' ^ (ai ^ k) = (ai ^ k)^(ai ^ k)= 0。所以存在一个合法的移动使得N-position转变为P-position局势。
3.根据该假设,当前被判断为P-position的局面无法移动到某个P-position。
证明:假设将ai改变成ai '能使得a1^a2^...^ai^...^an = a1^a2^...^ai ' ^...^an = 0,那么ai = ai ',而这种移动是不合法的。所以,当前被判断为P-position的局面无法移动到某个P-position。
那么我们现在就证明了对任意奇异局势(a1,a2,....an)都有a1^a2^...^an = 0的特征,同时,也将尼姆博弈模型从3堆推广到n堆。其实,这就是Bouton定理。
Bouton定理:状态(x1,x2,x3)为必败状态当且仅当x1^x2^x3=0,称为Nim和。
好了,现在证明完了,我们应该考虑如果在Nim博弈中获胜了,换句话说,在双方都采取最优策略的情况下,如何在己方是必胜态的情况下进行操作。
假定我们现在为先手,且局势为必胜局势。也就是a1 ^ a2 ^ ..... ^ an != 0,那么现在我们要将其中一个数ai减小为ai ',使得a1^a2^...^ai ' ^...^an = 0。首先,我们设k =a1^a2^...^ai^...^an,s = ai ^ k,那么问题就转化成了要找到一个 ai ' ,使得s ^ ai ' = 0,即 ai ’ = ai ^ k,再从数量为ai 的那堆中取出数量为ai - (ai ^ k)的数量的石头就可以了。
接下来附上两道例题,恰好解决的就是这个问题
例题一:
Being a Good Boy in Spring Festival
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3974 Accepted Submission(s): 2347
春节回家 你能做几天好孩子吗
寒假里尝试做做下面的事情吧
陪妈妈逛一次菜场
悄悄给爸爸买个小礼物
主动地 强烈地 要求洗一次碗
某一天早起 给爸妈用心地做回早餐
如果愿意 你还可以和爸妈说
咱们玩个小游戏吧 ACM课上学的呢~
下面是一个二人小游戏:桌子上有M堆扑克牌;每堆牌的数量分别为Ni(i=1…M);两人轮流进行;每走一步可以任意选择一堆并取走其中的任意张牌;桌子上的扑克全部取光,则游戏结束;最后一次取牌的人为胜者。
现在我们不想研究到底先手为胜还是为负,我只想问大家:
——“先手的人如果想赢,第一步有几种选择呢?”
35 7 90
1
#include<algorithm>#include<iostream>#include<cstdio>#include<cstring>using namespace std;int main(){ int n,i,sum,cnt; int Nim[105]; while(scanf("%d",&n) && n) { cnt=0; sum=0; for(i=0;i<n;i++) { scanf("%d",&Nim[i]); sum^= Nim[i]; } for(i=0;i<n;i++) { if(Nim[i]>(sum^Nim[i]))//如上所述,判断是否存在ai > ai ^ k,如果存在,对该堆进行操作。 cnt++; } printf("%d\n",cnt); } return 0;}例题二:
取(m堆)石子游戏
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1493 Accepted Submission(s): 869
245 4533 6 955 7 8 9 100
NoYes9 5Yes8 19 010 3
#include<algorithm>//和上一题几乎一样,只不过要输出具体的操作方案就是了。#include<iostream>#include<cstdio>#include<cstring>using namespace std;int Nim[200050];int main(){ int cnt, n; while(scanf("%d", &n) && n) { cnt = 0; for(int i=0; i<n; ++i) { scanf("%d", &Nim[i]); cnt ^= Nim[i]; } if(cnt == 0) { printf("No\n"); continue; } printf("Yes\n"); for(int i=0; i<n; ++i) { if(Nim[i] >= (Nim[i] ^ cnt)) printf("%d %d\n", Nim[i], Nim[i] ^ cnt); ///对ai > ai ^ k的堆操作,使留下数量为ai ^ k,此时(ai ^ k) ^ (ai ^ k) = 0,使对手面对必败局势。 } } return 0;}
- 浅谈Nim博弈 附hdu 2176 取(m堆)石子游戏 ,hdu 1850 Being a Good Boy in Spring Festival
- HDU 1850 Being a Good Boy in Spring Festival && hdu 2176 取(m堆)石子游戏 (尼姆博弈)
- HDU 1850 Being a Good Boy in Spring Festival 博弈Nim游戏
- HDU 1850 Being a Good Boy in Spring Festival(博弈·Nim游戏)
- [HDU](1850)Being a Good Boy in Spring Festival ---Nim博弈(博弈)
- Being a Good Boy in Spring Festival - HDU 1850 Nim
- hdu 1850 Being a Good Boy in Spring Festival (博弈)
- [博弈]HDU 1850 Being a Good Boy in Spring Festival
- HDU(1850) Being a Good Boy in Spring Festival (博弈)
- Being a Good Boy in Spring Festival - HDU 1850 博弈
- hdu 1850 Being a Good Boy in Spring Festival 博弈
- hdu 1850 Being a Good Boy in Spring Festival 博弈
- hdu 1850 Being a Good Boy in Spring Festival(博弈)
- hdu 1850 Being a Good Boy in Spring Festival Nim博弈
- 【Nim博弈】Hdu 1850 Being a Good Boy in Spring Festival
- [ACM] hdu 1850 Being a Good Boy in Spring Festival(Nim博弈)
- [Nim博弈]hdu 1850 Being a Good Boy in Spring Festival
- HDU 1850 Being a Good Boy in Spring Festival(nim博弈)
- 别让网站的性能影响你的业绩
- oracle的乐观锁和悲观锁
- 不实现Cloneable接口,实现clone()方法功能
- zoj 3778 Talented Chef
- 在你步入职业软件开发生涯那天起就该知道的五件事 --打倒我人生观
- 浅谈Nim博弈 附hdu 2176 取(m堆)石子游戏 ,hdu 1850 Being a Good Boy in Spring Festival
- USB描述符 包括bushound抓包
- 判断单链表里面有没有环
- java创建对象的几种方式
- QuartusII_13.0下载及破解工具地址
- cocos2dx3.0图像拼接(像素匹配)
- install hadoop2.2 trouble shooting
- 郑州大学2014 ACM省赛选拔赛 1001-画直线
- 进程是否采用3d指令的判断