取石子兒和拿撲克牌問題

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,那麼一定是先手贏。之外是後手贏。

發佈了231 篇原創文章 · 獲贊 36 · 訪問量 142萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章