首页 > 代码库 > nim(3)两堆石头的游戏
nim(3)两堆石头的游戏
在前面两个题目中,我们讨论了被称为"NIM(拈)“的这种游戏及其变种玩法和必胜策略,下面我们将讨论这类游戏的另一种有趣玩法。假设有两堆石头,有两个玩家会根据如下的规则轮流取石头。每人每次可以从两堆石头中各取数量相等的石头,或者仅从一堆石头中取出任意数量的石头;最后把剩下的石头一次拿光的人获胜。定义一个函数如下: bool nim(n,m) //n,m两堆石头的数量。要求返回一个布尔值,表明首先取石头的玩家是否能赢得这个游戏。
解法一:和朴素的素数筛选法一样,从最小数量的石头堆开始逐个排查,比如(1,2)这个石头堆就是不安全局面,所以这个数字组合就相当于排查出一个质数来,一次以此类推。自底向上的直到排查出所有不安全局面为止。
自己写的代码如下:(时间复杂度为O(n3))
#include <iostream> using namespace std; #define M 91//分别输入两堆石头的数量 #define N 56//分别输入两堆石头的数量 const int n=M>N?M:N; struct Stone { int a; int b; int flag; }s[n][n]; //两堆石头的游戏 bool NIM(int ,int ) { int i,j,t=n,i1=1,j2=2; while(t--) { int FLAG=0; for (i=0;i<n;i++) { for (j=i;j<n;j++) { if (s[i][j].a==s[i][j].b) { s[i][j].flag=1;//标志为1的项都是先手必胜的项 } if (s[i][j].a==i1||s[i][j].a==j2||s[i][j].a-i1==s[i][j].b-j2) { if (s[i][j].a<=i1&&s[i][j].b<=j2) { continue; } s[i][j].flag=1; } } } for (i=0;i<n;i++) { for (j=i+1;j<n;j++) { if (s[i][j].flag==0&&s[i][j].a>i1&&s[i][j].b>j2) { i1=s[i][j].a; j2=s[i][j].b; cout<<"("<<i1<<","<<j2<<") "; FLAG=1; if ((s[i][j].a==M&&s[i][j].b==N)||(s[i][j].a==N&&s[i][j].b==M)) { return false; } break; } } if (FLAG==1) { break; } } } return true; } void main() { int i,j; for (i=n-1;i>=0;i--) { for (j=i;j<n;j++) { s[i][j].a=i+1; s[i][j].b=j+1; } } if(NIM(M,N)) { cout<<"先手必赢"<<endl; } else { cout<<"先手必输"<<endl; } }
解法二:看到书上所给的一个公式,利用这个公式就可以求出所有不安全局面,但是对于这个公式的数学证明没看懂,我想真正面试的时候,我也不可能想到这种方法。
根据这个公式写得代码如下:(时间复杂度为O(1))
#include <iostream> #include <math.h> using namespace std; bool nim(int x,int y)//whether win the game { double a,b; a=(1+sqrt(5.0))/2; b=(3+sqrt(5.0))/2; if (x==y) { return true; } if (x>y) { swap(x,y);//ensure x<=y } if (x==(int)((y-x)*a)&&y==(int)((y-x)*b)) { return false; } else return true; } void nim(int num)//print all the unsafe points { double a,b; a=(1+sqrt(5.0))/2; b=(3+sqrt(5.0))/2; for (int i=0;i<=num;i++) { cout<<"("<<(int)(a*i)<<","<<(int)(b*i)<<") "; } cout<<endl; } void main() { cout<<nim(6,10)<<endl; nim(100); }
nim(3)两堆石头的游戏
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。