NIM(3)两堆石头的游戏

1. 问题描述

假设有两堆石头,有两个玩家会根据如下的规则轮流取石头:每人每次可以从两堆石头中各取出数量相等的石头,或者仅从一堆石头中取出任意数量的石头;最后把剩下的石头一次拿光的人获胜。请问在哪些局面(依据两堆石头中的石头个数)下,先取石头的玩家有必胜的策略

2. 解法

类似构造质数的筛选方法,这里我们利用找到的必输局面(后取的玩家有必胜策略)来筛去掉能通过一次操作达该必输局面的其它必胜局面(先取的玩家有必胜策略)。最后选出的局面都是必输局面。

  构造必胜策略:

如果一开始的局面就是必输局面,那么可能先取的玩家没有必胜策略(当然如果后取的玩家不太聪明,先取的玩家依然有可能能赢)。如果一开始的局面不是必输局面,那么先取的玩家一定有必胜策略,且必胜策略就是保证每次都将当前非必输局面转变为必输局面(后取的玩家必输)。

  先取者有必胜策略的局面为“安全局面”,而先取者无必胜策略的局面为“不安全局面”。通过筛选可得如下不安全局面表:

不安全局面表

N 1 2 3 4 5 6 7 8 9 10 ...
an 1 3 4 6 8 9 11 12 14 16 ...
bn 2 5 7 10 13

15

18 20 23 26 ...

  有了通项公式,我们就能更加简明地实现函数bool nim(n,m),这个函数的时间复杂度为O(min(m,n))。代码如下:

 package chapter1youxizhileNIM3;
/**
* 两堆石头的游戏
* @author DELL
*
*/
public class NIM3 {
/**
* 计算玩家是否能赢得游戏
* @param n 其中一堆石头的数量
* @param m 另一堆石头的数量
* @return 输赢状态
*/
public static boolean nim(int n, int m){
double a,b;
int temp;
a = (1+Math.sqrt(5.0))/2;
b = (3+Math.sqrt(5.0))/2;
if(m == n)
return true;
if(m < n){ //保证m>n
temp = m;
m = n;
n = temp;
}
int i = n;
while(i>=1){ //由于序号i值一定小于等于min(m,n)所以遍历查找
if((int)Math.floor(a*i)==n&&(int)Math.floor(b*i)==m)
return false;
i--;
}
return true;
}
public static void main(String[] args) {
if(nim(5,3))
System.out.println("(5,3)有必胜策略!");
else
System.out.println("(5,3)没有必胜策略!"); if(nim(3,6))
System.out.println("(3,6)有必胜策略!");
else
System.out.println("(3,6)没有必胜策略!");
} }

程序运行结果如下:

(5,3)没有必胜策略!
(3,6)有必胜策略!

3. 扩展问题

  1. 现在我们已经给出了一个判断先取者是否能够最终赢得游戏的判断函数,但是,游戏的乐趣在于过程,大家能不能根据本题的思路给出一个赢得游戏的必胜策略呢?即根据当前石头的个数,给出当前玩家下一步要怎么取石头才能必胜。

程序如下:

 package chapter1youxizhileNIM3;
/**
* 两堆石头的游戏
* @author DELL
*
*/
public class NIM3 {
/**
* 计算玩家是否能赢得游戏
* @param n 其中一堆石头的数量
* @param m 另一堆石头的数量
* @return 输赢状态
*/
public static boolean nim(int n, int m){
double a,b;
int temp;
a = (1+Math.sqrt(5.0))/2;
b = (3+Math.sqrt(5.0))/2;
if(m == n)
return true;
if(m < n){ //保证m>n
temp = m;
m = n;
n = temp;
}
int i = n;
while(i>=1){ //由于序号i值一定小于等于min(m,n)所以遍历查找
if((int)Math.floor(a*i)==n&&(int)Math.floor(b*i)==m)
return false;
i--;
}
return true;
} public static void result(int n,int m){
int min,max; //存储m,n中的最小值和最大值
int i;
if(m<=n){
min = m;
max = n;
}else{
min = n;
max = m;
}
if(m==n)
System.out.println("("+n+", "+m+")取后的状态为(0, 0)");
if(nim(n,m)){
for(i=1;i<=min;i++){
if(!nim(n-i,m-i)){
System.out.println("("+n+", "+m+")取后的状态为("+(n-i)+", "+(m-i)+")");
return;
}
if(!nim(n-i,m)){
System.out.println("("+n+", "+m+")取后的状态为("+(n-i)+", "+m+")");
return;
}
if(!nim(n,m-i)){
System.out.println("("+n+", "+m+")取后的状态为("+n+", "+(m-i)+")");
return;
}
}
for(i=min+1;i<=max;i++){
if(n>=m){
if(!nim(n-i,m)){
System.out.println("("+n+", "+m+")取后的状态为("+(n-i)+", "+m+")");
return;
}
}else{
if(!nim(n,m-i)){
System.out.println("("+n+", "+m+")取后的状态为("+n+", "+(m-i)+")");
return;
}
}
}
}else{
System.out.println("无论怎么取都没有必胜的策略!");
}
}
public static void main(String[] args) {
result(3,6);
result(6,6);
} }

程序运行结果如下:

(3, 6)取后的状态为(3, 5)
(6, 6)取后的状态为(0, 0)

  2. 取石头的游戏已经不少了,但是我们还有一种游戏要请大家思考,我们姑且叫它NIM(4):

  两个玩家,只有一堆石头,两人依次拿石头,最后拿光者为赢家。取石头的规则是:

    (a)第一个玩家不能拿光所有的石头。

    (b) 第一次拿石头之后,每人每次最多只能拿掉对方前一次所拿石头的两倍。

  那么,这个游戏有没有必胜的算法?(提示:好像和Fibonacci数列有关。)

  经分析可知,当这一堆石头的数量为Fibonacci值的时候,先拿者没有必胜策略。

判断的算法如下:

 package chapter1youxizhileNIM3;
/**
* 扩展问题
*  两个玩家,只有一堆石头,两人依次拿石头,最后拿光者为赢家。取石头的规则是:     (a)第一个玩家不能拿光所有的石头。     (b) 第一次拿石头之后,每人每次最多只能拿掉对方前一次所拿石头的两倍。   那么,这个游戏有没有必胜的算法?(提示:好像和Fibonacci数列有关。)
* @author DELL
*
*/
public class NIM4 {
/**
* 计算玩家是否能赢得游戏
* @param n 给定的一堆石头的数量
* @return 输赢状态
*/
public static boolean nim(int n){
int f1 = 1, f2 = 1; //Fibonacci数列的前两个值
int f3;
if(n==1)
return false;
do{
f3 = f1+f2;
f1 = f2;
f2 = f3;
}while(f3<n);
if(f3==n)
return false;
else
return true;
} public static void main(String[] args){
if(nim(3))
System.out.println("(3)有必胜策略!");
else
System.out.println("(3)没有必胜策略!");
if(nim(4))
System.out.println("(4)有必胜策略!");
else
System.out.println("(4)没有必胜策略!");
}
}

程序运行结果如下:

(3)没有必胜策略!
(4)有必胜策略!

第1章 游戏之乐——NIM(3)两堆石头的游戏的更多相关文章

  1. 第1章 游戏之乐——NIM(2)“拈”游戏分析

    NIM(2)“拈”游戏分析 1. 问题 有N块石头和两个玩家A和B,玩家A先将石头分成若干堆,然后按照BABA……的顺序不断轮流取石头,能将剩下的石头一次取光的玩家获胜.每次取石头时,每个玩家只能从若 ...

  2. 第1章 游戏之乐——NIM(1)一排石子的游戏

    NIM(1)一排石子的游戏 转载:编程之美-MIN(1)一排石头的游戏 1. 原题 1.1 题目 N块石头排成一行,每块石头有各自固定的位置.两个玩家依次取石头,每个玩家每次可以取其中任意一块石头,或 ...

  3. 编程之美 set 18 拈两堆石子游戏(3)

    题目 假设有两堆石头, 有两个玩家按照如下规则轮流取石头 每个人每次可以从两堆石头中取出数量相等的石头, 或者仅从一堆石头中取出任意数量的石头 最后把剩下的石头依次拿光的人取胜 首先取石头的人能否赢得 ...

  4. Poj 1067 取石子游戏(NIM,威佐夫博奕)

    一.Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子. ...

  5. 【转】Unity3D研究院之两种方式播放游戏视频

    http://www.xuanyusong.com/archives/1019   Unity3D中播放游戏视频的方式有两种,第一种是在游戏对象中播放,就好比在游戏世界中创建一个Plane面对象,摄像 ...

  6. NIM游戏,NIM游戏变形,威佐夫博弈以及巴什博奕总结

    NIM游戏,NIM游戏变形,威佐夫博弈以及巴什博奕总结 经典NIM游戏: 一共有N堆石子,编号1..n,第i堆中有个a[i]个石子. 每一次操作Alice和Bob可以从任意一堆石子中取出任意数量的石子 ...

  7. (linux shell)第二章--命令之乐(一)

    文章来自于我的个人博客:(linux shell)第二章--命令之乐(一)    上一章我们描写叙述了一些linux shell中须要注意的一些语法.接下来我们開始了解linux shell的经常使用 ...

  8. Python编写两个数的加减法游戏

    目标: 1.实现两个数的加减法 2.回答者3次输错计算结果后,输出正确结果,并询问回答者是否继续 1.使用常规函数实现两个数的加减法游戏 代码如下: #!/usr/bin/env python # - ...

  9. NIM(1) 一排石头的游戏

    最近在实习面试过程中,一个朋友遇到了该问题,从简单到复杂的思路如下,希望能给遇到相同问题的朋友一些启发和帮助.(内容来源网络和<编程之美>) 1.问题1 100个苹果 桌上有100个苹果, ...

随机推荐

  1. bjfu1109 最小公倍数和

    这题真是过了n年才a.最早是在2010年北大培训比赛上看到的这题,当时我不会,竹教主也不会,但他记下来了,研究一段时间后就会了,还把这题加到我校oj上.过了这么多年,我上网搜,关于这个问题的解题报告还 ...

  2. js获取浏览器基本信息:document.body.clientWidth/clientHeight/scrollWidth/scrollTop。(转)

    js获取浏览器基本信息:document.body.clientWidth/clientHeight/scrollWidth/scrollTop. 分类: js.jquery.ext.js技术2011 ...

  3. 遍历 集合 Dictionary 的时候修改集合 方法

    Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("1" ...

  4. javascript AES加密 C#AES解密实现

    首先需要引入js类库 crypto-js(开源),地址:http://code.google.com/p/crypto-js 现在很多人无法打开这个地址不要紧,下面我们会将全部代码贴出来 需要引入 a ...

  5. php 解决微信昵称emoji表情插入MySQL报错

    在PHP接受到微信用户昵称入库的时候报错 原因:utf-8 最大3个字节,而emoji占4个字节 解决办法: 1.修改mysql 数据库的字符集,改为utf8mb4,但是前提是MySQL的版本需要5. ...

  6. 利用ASP.NET MVC源代码调试你的应用程序[转]

    由于项目需要,最近学起asp.net mvc.昨天遇到ViewData和TempData他们之间的分别这样让我纠结的问题.有园友强烈建议我去看ASP.NET MVC的源代码.所以,我想到如何在调试AS ...

  7. ACCESS TOKEN

    Access Token 在微信公众平台接口开发中,Access Token占据了一个很重要的地位,相当于进入各种接口的钥匙,拿到这个钥匙才有调用其他各种特殊接口的权限. access_token是公 ...

  8. bfs CCF2016第七次 游戏

    // bfs CCF2016第七次 游戏 // 思路: // O(300*100*100) // 直接暴搜 // 注意,同一格同一时间不能经过两次!!! #include <bits/stdc+ ...

  9. MUSIC算法学习笔记

    MUSIC即多重信号分类. MUSIC算法仅能估计非相干关信源,对相干信源,其性能将随信源间的相 关系数的增加而逐渐降低,直至完全恶化. 阵列信号处理的只要问题包括:波束形成技术,零点形成技术,空间谱 ...

  10. 阿里云slb http https配置