`

<游戏> 取石子

阅读更多

Tang和Jiang非常喜欢玩一种有趣的小游戏: 有N个石子,两人轮流从中取出1个, 3个或4个石子,当石子被取空时,游戏结束。最后一个取石子的人获胜, 第一次总是Tang取. 当然,他们俩都足够聪明,总会采取最优的策略。

Input
每行会有一个正整数N(N<=100000), 代表石子的个数, N=0 代表输入结束
Output
输出获胜人的名字。

Sample Input
1 //石头数量为1
2
0
Sample Output
Tang //石头数量为1的时候,总是Tang会赢
Jiang

 


分治法: 穷举出所有可能的取石头方案。

 

      算法思想,假设两个玩家分别pid编号为0和1。f(n, pid)表示当前一轮获胜的玩家编号(如果f=0,表示获胜玩家是0),其中n表示当前一轮的石头总数,pid表示当前一轮的玩家标号。

 

      考虑分治算法的思想,当前一轮的胜负结果取决于对下一轮各种情况的结果的统计。这个统计有两种情况:

      1、当前一轮玩家pid=0,那么他取石头的可能性为1,3或4。则下一轮玩家pid=1的情况有三种: f(n-1, 1),f(n-3,1),f(n-4,1)。如果这三种情况的f()函数值至少有一个是0,不妨假设f(n-1, 1)=0,根据题目条件的" 们俩都足够聪明,总会采取最优的策略。 " ,那么当前一轮pid=0的玩家一定会选择取1个石头,结果也一定是pid=0赢。

           因此当pid=0时, f(n ,0)=f(n-1, 1)&f(n-3, 1)&f(n-4, 1)

      2、当前一轮玩家pid=1,那么下一轮三种情况下只要有一个f()函数值为1,则结果一定是pid=1赢。即

           当pid=1是, f(n ,1)=f(n-1, 0)|f(n-3, 0)|f(n-4, 0)

 

      下面是源代码:

public class RecurStonePlay {
	private static final String[] PLAYER={"Tang","Jiang"};
	/**
	 * 当前轮到第pIdx个PLAYER从剩下的stoneNum块石头中取石头获胜的情况
	 * @param stoneNum 当前石头总数
	 * @param pIdx 取石头的人的ID
	 * @return 在当前这种情况下,能够取胜的PLAYER的ID
	 */
	public static int turn(int stoneNum,int pIdx){
		
		//当前只有1,3,4块石头时,则当前PLAYER[pIdx]能够取胜
		if(stoneNum==1||stoneNum==3||stoneNum==4) return pIdx;
		//当前只有2块石头时,则PLAYER[(pIdx+1)%2]能取胜
		if(stoneNum==2) return (pIdx+1)%2;
		
		//如果当前是PLAYER[0]取石头,则只要取1,3,4块三种情况中一种情况下能够取胜,则PLAYER[0]获胜。
		//使用&运算,如果有一个0,则结果为0
		if(pIdx==0)
			return turn(stoneNum-1,(pIdx+1)%2)&turn(stoneNum-3,(pIdx+1)%2)&turn(stoneNum-4,(pIdx+1)%2);
		//与上面情况相反,如果有一个1,则结果为1
		else
			return turn(stoneNum-1,(pIdx+1)%2)|turn(stoneNum-3,(pIdx+1)%2)|turn(stoneNum-4,(pIdx+1)%2);
	}
	
       //测试
	public static void main(String[] args) {
                //石头总数为5块,PLAYER[0]开始先玩
		System.out.println(PLAYER[RecurStonePlay.turn(5,0)]);
	}
}

 

上面的方法时间复杂度太高,那么 是否能够通过对当前一轮石头总数的判断,可以知道是当前玩家赢(先手赢),还是下一轮的玩家赢(后手赢)呢? 

 

我们假设先手玩家是Player1,后手玩家是Player2。用上面的程序运行1-30个石头,并输出赢的情况(其中0代表Player1赢,1代表Player2赢)。

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27   28  29  30

1   0  0  0  0  1   0  1    0    0    0    0    1    0    1     0    0    0    0    1     0    1     0    0    0    0      1    0    1

 

我们可以发现,凡是mod 7 余2或0的石头数目,都是后手赢,其他情况都是先手赢。 我们来证明一下:

 

(1) stoneNum=1,2,3,4时就不证明了。

(2) 当stoneNum=2的时候,是Player2赢。我们能够想到,如果Player1抽取石头后,能使得Player2玩的时候手头上的石头数量为2。那么Player1一定赢。也就是说(2+1=3),(2+3=5),(2+4=6)的石头数量一定导致Player1赢。

(3) 当stoneNum=7的时候,Player1无论抽1,3,4块石头中的任意情况,都会使得Player2玩的时候手头上的石头数量为6,4,3。这三种石头数量都是当前玩家赢(Player2赢)。因此7块石头一定是Player2赢。

(4) 当stoneNum=7的时候,情况与(2)相同。因此(7+1=8),(7+3=10),(7+4=11)的石头数量一定是Player1赢。

(5) 当stoneNum=9的时候,情况与(3)相同。因此9块石头一定是Player3赢。

(6) 依次下去,我们就能够得出这个结论:

 

策略:如果当前石头数量stoneNum%7==2||stoneNum%7==0,那么一定是后手赢。除此之外是先手赢。

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    取石子游戏_博弈

    一、游戏 游戏A: ...两人轮流按下列规则取走一些石子,游戏的规则如下: 2. 每一步应取走至少一枚石子; 3. 每一步只能从某一堆中取走部分或全部石子; � 如果谁无法按规则取子,谁就是输家。 。。。。。。

    取石子之三类博弈(acm算法)

    博弈论,主要讲述了取石子游戏中所涉及到的三类博弈论问题

    取石子游戏类分析的分析讨论(转)

    取石子是经典的算法考试题目,这个PPT是我在百度文库下载的。上传在CSDN是为了备份。下载免任何积分的

    取石子的三种博弈

    这是博弈算法-取石子的游戏,这是我自己整理的,自己感觉很有用,希望对大家有好处。

    常用经典算法及实例讲解

    内涵经典程序,论文选刊 部分如下:ApSimon 的造币厂问题,华容道游戏的搜索策略,八女王问题,高斯算法,取石子游戏,最大及最小素数问题……&lt;br&gt;&lt;br&gt;&lt;br&gt;

    组合博弈取石子游戏.pdf

    组合博弈取石子游戏.pdf

    组合博弈 取石子游戏.pdf

    组合博弈 取石子游戏.pdf

    两个人取一堆石子,判断先后手胜,菲波那切数列

    H 取石子游戏.c 简单的博弈题

    c语言之取石子游戏(ACM题目.doc

    c语言之取石子游戏(ACM题目

    取石子游戏类分析和分析讨论.ppt

    取石子游戏类分析和分析讨论.ppt

    算法-取石子游戏(信息学奥赛一本通-T1218).rar

    算法-取石子游戏(信息学奥赛一本通-T1218).rar

    扔石子游戏分析c语言实现!

    有N块石头和两个玩家A和B,玩家A先将石头分成若干堆,然后按照BABA……的顺序不断轮流取石头,能将剩下的石头一次取光的玩家获胜。每次取石头时,每个玩家只能从若干堆石头中任选一堆,取这一堆石头中任意数目(大于...

    Qt 实现NIM游戏

    Nim取子游戏是由两个人面对若干堆硬币(或石子)进行的游戏。设有k&gt;=1堆硬币,各堆分别含有N1,N2,……NK枚硬币。游戏的目的就是选择最后剩下的硬币。游戏法则如下: 1.两个游戏人交替进行游戏(游戏人I和游戏人...

    wangjunrui666#bzoj-problem##2000. [Hnoi2010]stone 取石头游戏1

    然后两个玩家轮流来取石子,每次每个玩家可以取走一堆中的所有石子,但有一个限制条件:一个玩家若要取走一堆石子,则与这堆石子相邻的某堆石子已被取走(之前被某个玩家取

    组合游戏.rar

    组合游戏 sg函数 博弈论 acm竞赛 取石子游戏

    Nim.rar_The Game of Nim_acm nim game_nim_nim 游戏_nim.cpp

    在愚蠢模式中,在轮到计算机时,简单地取走随机数目(介于1到n/2之间)的石子 在聪明模式中,计算机每次取走一定数目的石子,使得剩下的石子数目是2的某次幂减1,例如3,7,15,31,63.这总是可行的,除非当前的石子数正好是2的...

    北邮电子院专业实验(五道题)

    1、自然数问题(10 分) ...游戏开始由两个人轮流取石子。游戏规定, 每次有两种不同的取法: 一是可以在任意的一堆中取走任意多的石子; 二是可以在两堆中同时取走相同数量的石子。 最后把石子全部取完者为胜者。

    nim-game.rar_nim_nim game_系统

    在愚蠢模式中,在轮到计算机时,简单地取走随机数目(介于1到n/2之间)的石子 在聪明模式中,计算机每次取走一定数目的石子,使得剩下的石子数目是2的某次幂减1,例如3,7,15,31,63.这总是可行的,除非当前的石子数正好是2的...

    拆分-Nim游戏

    题意:给定n堆石子,两位玩家轮流操作,每次操作可以取走其中的一堆石子,然后放入两堆规模更小的石子(新堆规模可以为0,且两个新堆的石子总数可以大于取走的那堆石子数),最后无法进行操作的人视为失败。...

    ACM博弈论资料合集

    我自已整理的ACM博弈论资料 包括到NIM取石子游戏 还有万能的SG函数 希望对大家有用

Global site tag (gtag.js) - Google Analytics