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