`

<游戏> 取石子

阅读更多

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,那么一定是后手赢。除此之外是先手赢。

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    取石子游戏_博弈

    在这个特定的取石子游戏中,我们有两个玩家,甲和乙,他们面对多堆石子,每堆石子的数量可以任意设定。游戏的目标是按照一定的规则尽可能地取走石子,使得对手无法再按照规则进行操作,从而成为赢家。 【游戏规则】...

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

    在取石子游戏中,博弈论提供了一套分析方法,帮助玩家理解游戏的本质,并制定取胜策略。本文将深入探讨取石子游戏中涉及的三种博弈论问题——巴什博奕、威佐夫博奕和尼姆博奕。 #### 巴什博奕(Bash Game) 巴什...

    组合博弈取石子游戏.pdf

    组合博弈取石子游戏 组合博弈取石子游戏是游戏理论中的一种经典问题,该游戏涉及到数学、逻辑和策略等多方面的知识。在本资源中,我们将对取石子游戏进行深入分析,讨论游戏的规则、策略和数学原理。 一、游戏规则...

    取石子的三种博弈

    取石子游戏中的三种博弈——巴什博弈、威佐夫博弈以及尼姆博弈,分别展示了不同条件下的游戏规则与获胜策略。通过数学分析与逻辑推理,我们可以深入理解这些游戏背后的原理,并掌握有效的应对策略。

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

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

    组合博弈 取石子游戏.pdf

    组合博弈 取石子游戏.pdf 组合博弈是一类需要策略和技巧的游戏,取石子游戏是其中的一种。游戏规则是两人轮流拿石子,规定谁取到最后一颗石子谁就胜出。在了解石子总数的情况下,如何快速预测谁将会胜出?我们可以...

    今日头条XX前端工程师笔试题.pdf

    题目中提到的`&lt;datalist&gt;`元素可以为输入字段提供预定义的选项列表,而`&lt;output&gt;`元素用于显示计算结果或其他由脚本生成的内容。`&lt;legend&gt;`并不是HTML5新增的,它在HTML4中就已存在,用来定义fieldset元素的标题。 ...

    今日头条XX前端工程师笔试题.docx

    小今想要必胜,应该先手取走1个石子,这样无论小条取1、2还是3个石子,小今都能保证在下一次取走剩余石子的总数,使得两堆石子的数量相等,然后在接下来的回合中保持这个策略。 11. HTTP与HTTPS: HTTP协议使用TCP...

    AcWing 1321. 取石子(博弈dp)(csdn)————程序.pdf

    代码使用了C++语言,并定义了一些常用的宏定义,如`db`表示double类型,`ll`表示long long类型,`Pir`表示pair&lt;int, int&gt;,以及`fi`和`se`分别表示pair的第一元素和第二元素。`pb`是push_back的缩写,`m_p`用于创建...

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

    c语言之取石子游戏(ACM题目) 在这个游戏中,我们需要从两堆石子中取石子,游戏规定,每次可以在任意的一堆中取走任意多的石子,也可以在两堆中同时取走相同数量的石子。我们的目标是让先取者获胜。 首先,我们...

    取石子的策略.pdf

    ### 取石子游戏策略与二进制异或操作的应用 #### 概述 本文探讨了一个经典的策略游戏——取石子游戏,并通过引入二进制中的异或操作(XOR)来解决该游戏的一种变体。游戏规则设定为:存在多堆石子(N堆),每堆石子...

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

    《算法-取石子游戏(信息学奥赛一本通-T1218)》这个压缩包文件中的主题是关于信息学奥赛中的一个经典问题——取石子游戏。这是一个涉及策略和逻辑思维的数学游戏,通常出现在编程竞赛或算法训练中,旨在锻炼参赛者...

    华为模拟机试题

    #### 取石子游戏 **问题描述:** - 有一堆石子,两个人轮流取石子。先取的人第一次可以取任意多个石子,但不能全部取完。之后每次取石子的数量不能超过上次取石子数量的两倍。谁取到最后一个石子谁获胜。 **解决...

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

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

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

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

    java 完成Nim石子游戏.docx

    通过分析游戏规则,我们可以发现,如果我能赢,那么最后轮到我取石子的时候必须要剩下 1~3 颗石子,这样我才能一把拿完。如何营造这样的一个局面呢?显然,如果对手拿的时候只剩 4 颗石子,那么无论他怎么拿,总会...

    关于石子算法问题解法实例

    游戏的基本规则是:有两个玩家,一堆或多堆石子,每轮玩家可以取走任意数量的石子,但必须从同一堆中取。谁取走最后一颗石子,谁就赢得游戏。在更复杂的形式中,可能有多个石子堆,每个堆有不同的石子数量,玩家需要...

    石子合并问题共1页.pdf.zip

    2. 状态转移:对于每一堆石子,考虑所有可能的取石子数量(在限制范围内),如果当前玩家取走这些石子后,对方无法赢得游戏,则当前玩家有获胜策略。 最后,根据dp数组的最后一行,我们可以判断先手玩家是否能赢得...

    组合游戏入门讲解

    取石子游戏是一种经典的组合游戏,通过这个游戏我们可以了解到组合游戏中的一些基本概念和解决策略。 **游戏规则:** - 游戏由两名玩家(玩家I和玩家II)参加。 - 游戏开始时有21枚石子放在桌子上。 - 玩家轮流从...

Global site tag (gtag.js) - Google Analytics