取石子儿和拿扑克牌问题

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

算法思想(使用递归):

当剩余为134的时候先手者必胜;如果当前数目不是这三个数字,则递归采用去134,只要其中有一种方式使得剩下的字儿使对方输,则先手者必胜;否则后手者胜。代码如下:

#include <iostream>
using namespace std;

bool win(int n){
	if(1==n || 3==n || 4==n)
		return true;
	if(2==n)
		return false;
	//只要有一种方案当取完后使对方输,则先手必胜
	//这一切都是基于“双方都足够聪明”的前提
	if(!win(n-1) || !win(n-3) || !win(n-4))
		return true;
	else 
		return false;
}

int main(){
	bool flag = win(15);
	if(true == flag)
		cout << "win..." << endl;
	else
		cout << "lose..." << endl;
	
	return 0;
}


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

我们可以发现,凡是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,那么一定是后手赢。除此之外是先手赢。

从这道题目又想到了以前看到的一个题目:

假如有10枚硬币,由你和对手两个人轮流拿,每次只能拿1个、2个或4个;拿走最后一枚硬币的人,算输。请问:有没有必赢的可能?

算法思想(使用递归):

当剩余为124的时候先手者必胜;如果当前数目不是这三个数字,则递归采用去124,只要其中有一种方式使得剩下的字儿使对方输,则先手者必胜;否则后手者胜。代码如下:

#include <iostream>
using namespace std;

bool win(int n){
	if(1==n || 2==n || 4==n)
		return true;
	if(3==n)
		return false;
	//只要有一种方案当取完后使对方输,则先手必胜
	//这一切都是基于“双方都足够聪明”的前提
	if(!win(n-1) || !win(n-2) || !win(n-4))
		return true;
	else 
		return false;
}

int main(){
	bool flag = win(15);
	if(true == flag)
		cout << "win..." << endl;
	else
		cout << "lose..." << endl;
	
	return 0;
}


同样如果按照上面分析数字的方法来分析则会非常简单:

我们可以发现,如果剩余的数字是3的整倍数的时候则先手输,若当前数目模3后余124,则先手赢:

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

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

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

(4) 当stoneNum=9的时候,情况与(2)相同。

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

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

你可能感兴趣的:(游戏,算法)