第1章 游戏之乐——NIM(3)两堆石头的游戏
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章 游戏之乐——NIM(2)“拈”游戏分析
NIM(2)“拈”游戏分析 1. 问题 有N块石头和两个玩家A和B,玩家A先将石头分成若干堆,然后按照BABA……的顺序不断轮流取石头,能将剩下的石头一次取光的玩家获胜.每次取石头时,每个玩家只能从若 ...
- 第1章 游戏之乐——NIM(1)一排石子的游戏
NIM(1)一排石子的游戏 转载:编程之美-MIN(1)一排石头的游戏 1. 原题 1.1 题目 N块石头排成一行,每块石头有各自固定的位置.两个玩家依次取石头,每个玩家每次可以取其中任意一块石头,或 ...
- 编程之美 set 18 拈两堆石子游戏(3)
题目 假设有两堆石头, 有两个玩家按照如下规则轮流取石头 每个人每次可以从两堆石头中取出数量相等的石头, 或者仅从一堆石头中取出任意数量的石头 最后把剩下的石头依次拿光的人取胜 首先取石头的人能否赢得 ...
- Poj 1067 取石子游戏(NIM,威佐夫博奕)
一.Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子. ...
- 【转】Unity3D研究院之两种方式播放游戏视频
http://www.xuanyusong.com/archives/1019 Unity3D中播放游戏视频的方式有两种,第一种是在游戏对象中播放,就好比在游戏世界中创建一个Plane面对象,摄像 ...
- NIM游戏,NIM游戏变形,威佐夫博弈以及巴什博奕总结
NIM游戏,NIM游戏变形,威佐夫博弈以及巴什博奕总结 经典NIM游戏: 一共有N堆石子,编号1..n,第i堆中有个a[i]个石子. 每一次操作Alice和Bob可以从任意一堆石子中取出任意数量的石子 ...
- (linux shell)第二章--命令之乐(一)
文章来自于我的个人博客:(linux shell)第二章--命令之乐(一) 上一章我们描写叙述了一些linux shell中须要注意的一些语法.接下来我们開始了解linux shell的经常使用 ...
- Python编写两个数的加减法游戏
目标: 1.实现两个数的加减法 2.回答者3次输错计算结果后,输出正确结果,并询问回答者是否继续 1.使用常规函数实现两个数的加减法游戏 代码如下: #!/usr/bin/env python # - ...
- NIM(1) 一排石头的游戏
最近在实习面试过程中,一个朋友遇到了该问题,从简单到复杂的思路如下,希望能给遇到相同问题的朋友一些启发和帮助.(内容来源网络和<编程之美>) 1.问题1 100个苹果 桌上有100个苹果, ...
随机推荐
- 《Python基础教程(第二版)》学习笔记 -> 第九章 魔法方法、属性和迭代器
准备工作 >>> class NewStyle(object): more_code_here >>> class OldStyle: more_code_here ...
- linux常用命令之--文件打包与压缩命令
linux的文件打包与压缩命令 1.压缩与解压命令 compress:用于压缩指定的文件,后缀为.z 其命令格式如下: compress [-d] 文件名 常用参数: -d:解压被压缩的文件(.z为后 ...
- OpenGL超级宝典第5版&&GLSL法线变换
在GLSL中,有一些情况需要把局部坐标系下的向量或点转换到视点坐标系下,如光照计算时,需要把法向转化到视点坐标系.如果是模型上一点p 转化到视点坐标系下,直接(model-view matrix )* ...
- Fedora22(Gnome桌面)安装Chrome
1.从官网上(http://www.google.cn/chrome/)下载到相对应系统版本的rpm包.这里我的是: google-chrome-stable_current_x86_64.rpm 此 ...
- 添加删除ASM磁盘
创建磁盘: [root@kel ~]# oracleasm createdisk KEL3 /dev/sdf1 Writing disk header: done Instantiating disk ...
- 使用Google Chart API绘制组合图
Google Chart API 绘图 组合图作者:方倍工作室 地址: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN& ...
- Tkinter教程之Message篇
本文转载自:http://blog.csdn.net/jcodeer/article/details/1811326 '''Tkinter教程之Message篇'''#Message也是用来显示文本的 ...
- Apache Spark Shark的简介
Shark是构建在Spark和Hive基础之上的数据仓库. 目前,Shark已经完成学术使命,终止开发,但其架构和原理仍具有借鉴意义. 它提供了能够查询Hive中所存储数据的一套SQL接口,兼容现有的 ...
- CodeForces 682A Alyona and Numbers (水题)
Alyona and Numbers 题目链接: http://acm.hust.edu.cn/vjudge/contest/121333#problem/A Description After fi ...
- Spring Auto proxy creator example
In last Spring AOP examples – advice, pointcut and advisor, you have to manually create a proxy bean ...