Nim Game是非常著名的游戏,它的变体也很多,在《编程之美》上也用了三章讲解它。 Wikipedia  上说的很详细,本文则是在对wiki上的内容阅读后的个人理解。

游戏概述:
有M堆石子,每堆石子的个数不一定相同,Bob和Alice交替取石子,只能在一堆石子上取,取的数目任意,但不能为0,也不能大于此堆石子的数目。获胜的判定有两种:一种是谁先把石子去完谁获胜,这种叫Normal Play;另一种是最最后把石子取完谁输,这种叫Misere Play。
假设有M堆石子,(H1,H2...HM),XOR(H1...HM) = X,我们的目标是将 (H1,H2...HM)变为(0,0...0),即XOR()=0,那么我们说任何XOR()=0的情况都是“安全状态”,对于Normal Play来说,取石子的那个人都想让自己取完石子后,石子堆为“安全状态”。
存在两个定理:
  • 任何“不安全状态”都可以通过一次取石子变为“安全状态”
  • 任何“安全状态”都通过一次取石子只能变为不安全状态
所以,在Normal Play情况下,初始状态很重要,如果初始状态为“不安全状态”,Bob获胜(先取者获胜),否则Alice获胜。
那在Misere Play情况下又怎么样那,先看一下两个特殊情况:
  1. 所有的堆的石子都是1,且有偶数个堆,那么Bob一定获胜
  2. 所有的堆的石子都是1,且有奇数个堆,那么Alice一定获胜
好的,任何取石子者都希望自己去完后,存在上面“2”提到的情况——所有的石子堆都不大于2,且有奇数个大小为1的堆。
那么先取者Bob怎样可以使自己获胜呢:
  • 如果一开始就是上面“1”提到的状态,Bob必输
  • 如果一开始就是上面“2”提到的状态,Bob必胜
  • 不是“1”“2”状态,初始状态是“不安全状态”,Bob一开始完全可以按“Normal Play”的方式取石子,当发现可以使石子产生奇数个1时,则不按“Normal Play”的方式去取了,让其变为奇数个1。下面证明一下为什么这样Bob就会获胜:如果Alice想产生一个奇数个1的不安全状态,那Alice一定是从一个安全状态产生一个不安全状态的(因为Bob先取,他总会产生一个安全状态),那么产生奇数个1的安全状态就是“偶数个1”,此时Bob便会再取一个石子,直接产生一个奇数个1的不安全状态,不需要Alice产生
  • 不是“1”“2”状态,初始状态是“安全状态”,Bob怎么取都会是一个“不安全状态”,Bob想让此状态为奇数个1,但可以达到此状态的安全状态是偶数个1,这是“1”提到的情况,矛盾。因此Bob不可能产生奇数个1,因此决定权在Alice手上了,Alice会获胜。
假设初始状态是不安全状态,Bob要怎样取石子才能产生一个安全状态呢?方法很简单。
我们假设XOR()=X,将X于每一堆石子的数量T做异或操作,如果结果小于T,则Bob将取此堆的石子,取得个数为T-T^X。
那么《编程之美》的扩展第一题也就解决了。
下面的代码实现了上面讲的内容:
public class NimClass {private int XOR(int[] heaps){int ret = 0;for(int i=0;i<heaps.length;i++)ret ^= heaps[i];return ret;}private int max(int[] heaps){int ret =0;for(int i=0;i<heaps.length;i++)if(heaps[i]>ret)ret = heaps[i];return ret;}/** If Pair.nb_remove is zero , it means that this taker will lose.*/public Pair nim( int[] heaps, boolean misere){int X = XOR(heaps);if(X==0){/* The safe state */if(max(heaps) > 1)return new Pair (-1,0);else{for(int i=0;i<heaps.length;i++)if(heaps[i]==1){heaps[i]=0;return new Pair (i,1);}return new Pair (-1,0);}}else{/* The unsafe state */int chosen_heap=-1,nb_remove=-1;for(int i=0;i<heaps.length;i++)if((heaps[i]^X)<heaps[i]){chosen_heap = i;nb_remove = heaps[i]-(heaps[i]^X);heaps[i] = heaps[i]^X;break;}boolean hasTowMoreHeap = false;int oneHeapNum = 0;for(int i=0;i<heaps.length;i++)if(i!=chosen_heap){if(heaps[i]>1){hasTowMoreHeap = true;break;}else if (heaps[i]==1) oneHeapNum++;}if(misere){if(hasTowMoreHeap)return new Pair (chosen_heap,nb_remove);else{heaps[chosen_heap] = 1;return new Pair (chosen_heap, nb_remove-1);}}else{return new Pair (chosen_heap, nb_remove);}}}class Pair{int chosen_heap ,nb_remove ;public Pair(int chosen_heap, int nb_remove){this.chosen_heap = chosen_heap;this.nb_remove = nb_remove;}}}

Nim理论初探——编程之美1.12相关推荐

  1. 编程之美2.12 快速寻找满足条件的两个数

      这道题目的意思是,在一个数组中寻找两个数,使这两个数的和等于给定的数(找到任意一组就可以了).       题目读完之后,感觉这道题目还是很简单的,就是遍历数组呗,走两遍,即可以在O(n2)时间复 ...

  2. 编程之美2.10:寻找数组中的最大值和最小值

    编程之美2.10: 对于一个有N个整数组成的数组,需要比较多少次才能把最大值和最小值找出来呢? 算法的思想是: 分而治之 测试数据:---------------------------------- ...

  3. 编程之美2.1 求二进制中1的个数

    最近一段的时间,一直在看编程之美之类的算法书籍,刚开始看编程之美,感觉到难度太大,有时候也不愿意去翻动这本书,不过,经过一段时间的修炼,我也彻底的喜欢上这本书了, 书中的算法涉及到很多方面,树,链表, ...

  4. 2017“编程之美”终章:AI之战勇者为王

    编者按:8月15日,第六届微软"编程之美"挑战赛在选手的火热比拼中圆满落下帷幕."编程之美"挑战赛是由微软主办,面向高校学生开展的大型编程比赛.自2012年起, ...

  5. Java 并发编程之美:并发编程高级篇之一-chat

    借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了.相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作 ...

  6. Java 并发编程之美:并发编程高级篇之一

    借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了.相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作 ...

  7. 二叉树中节点的最大的距离(编程之美3.8)

    问题来源:<编程之美>3.8 求二叉树节点的最大距离 如果把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两个节点之间的个数. 写一个程序求一 ...

  8. 编程之美1:那些关于1的个数的经典面试题

    那些关于1的个数的经典面试题 好长时间没有练算法了,笔试题一做,发现非常吃力,所以近日来找来<编程之美>一书来看看练练.为了激励自己多练,楼楼可能会出个专栏什么的,感兴趣的同学我们可以一起 ...

  9. 中国象棋将帅问题java_编程之美:中国象棋将帅问题

    Author: Fox 晚上没有加班,打游戏打到9点过,后面就又看了一道<编程之美>的题目<中国象棋将帅问题>. 题目:下过中国象棋的朋友都知道,双方的"将" ...

  10. python编程之美pdf_Python编程之美:最佳实践指南

    领取成功 您已领取成功! 您可以进入Android/iOS/Kindle平台的多看阅读客户端,刷新个人中心的已购列表,即可下载图书,享受精品阅读时光啦! - | 回复不要太快哦~ 回复内容不能为空哦 ...

最新文章

  1. dumpbin发现没有入口函数_详解VS2019 dumpbin查看DLL的导出函数
  2. 再见QQ,再见QQ游戏!
  3. youtube-dl
  4. 强化学习之基于伪计数的探索算法
  5. 精致全景图 | 程序是如何运行起来的
  6. 如果没有Visual Studio 2015,我们如何创建.NET Core项目 ?
  7. Atitit 艾提拉博士带来“深度?广度?高度 人员的职业发展之路 ”的主题分享。 目录 1.1. 技术团队气氛的区别 开发架构模式 2 1.2. 技术人员的职业发展有哪些路线? 3 1.3. 主
  8. 凸优化第八章几何问题 8.4极值体积椭圆
  9. Excel如何快速提取红色字体文本
  10. 【电机测速】M法、T法、M/T法测速系统设计实现
  11. linux磁盘加密bitlocker,Azure Disk Encryption(Azure磁盘加密)能用在Linux和Windows下
  12. IndexError: Caught IndexError in DataLoader worker process 0.
  13. 3.Tom猫的实现(帧动画播放)
  14. 面向对象的分析(Object Oriented Analysis,OOA)模型有三种:功能模型 (用例图)对象模型(类图) 动态模型(状态图)
  15. 羊车门问题的python代码_作业:羊车门问题
  16. word如何关闭批注模式【教程】
  17. 经典卷积和深度卷积的神经网络
  18. dva自定义组件及使用方法
  19. 2022最新最全的pytest配置文件pytest.ini
  20. ELF文件格式, ELF文件是什么,里面包含什么内容

热门文章

  1. 重磅出击: Rancher 2.4.x 迁移自定义 k8s 集群
  2. 数字序号的级别与文章层次结构的关系
  3. STM32 触摸屏触摸功能
  4. Lipschitz function 是什么?Lipschitz continuous呢?
  5. 蓝牙耳机能链接计算机,蓝牙耳机,小编教你蓝牙耳机怎么连接电脑
  6. 如何制作Android语音机器人
  7. linux基本防护 /病毒检测
  8. Using Technorati Tags
  9. 为RK3399,树莓派等开发板安装安卓、Linux等系统
  10. 小鑫の日常系列故事(七)——小纸条