Tang和Jiang非常喜歡玩一種有趣的小遊戲:有N個石子,兩人輪流從中取出1個, 3個或4個石子,當石子被取空時,遊戲結束。最後一個取石子的人獲勝,第一次總是Tang取.當然,他們倆都足夠聰明,總會採取最優的策略。
算法思想(使用遞歸):
當剩餘爲1、3、4的時候先手者必勝;如果當前數目不是這三個數字,則遞歸採用去1或3或4,只要其中有一種方式使得剩下的字兒使對方輸,則先手者必勝;否則後手者勝。代碼如下:
#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個;拿走最後一枚硬幣的人,算輸。請問:有沒有必贏的可能?
算法思想(使用遞歸):
當剩餘爲1、2、4的時候先手者必勝;如果當前數目不是這三個數字,則遞歸採用去1或2或4,只要其中有一種方式使得剩下的字兒使對方輸,則先手者必勝;否則後手者勝。代碼如下:
#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後餘1、2、4,則先手贏:
(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,那麼一定是先手贏。之外是後手贏。