取(2堆)石子游戏
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2622 Accepted Submission(s): 1594
Problem Description
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。如果你胜,你第1次怎样取子?
Input
输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,且a<=b。a=b=0退出。
Output
输出也有若干行,如果最后你是败者,则为0,反之,输出1,并输出使你胜的你第1次取石子后剩下的两堆石子的数量x,y,x<=y。如果在任意的一堆中取走石子能胜同时在两堆中同时取走相同数量的石子也能胜,先输出取走相同数量的石子的情况.
Sample Input
1 2
5 8
4 7
2 2
0 0
Sample Output
0
1
4 7
3 5
0
1
0 0
1 2
Author
Zhousc
Source
[x y]可以转换三种状态(1)[x-k,y] (2)[x,y-k] (3)[x-k,y-k]
只要这三种里面出现至少一种输的状态 [x,y]就是必胜态 否则[x,y]必败
所以我们可以打表发现规律
打表代码
1 const int N=100; 2 int a[N][N]; 3 int main(){ 4 int i,j,k; 5 a[0][0]=0; 6 for(i=1;i<N;i++){ 7 a[0][i]=a[i][0]=1; 8 } 9 for(i=1;i<N;i++){ 10 for(j=1;j<N;j++){ 11 a[i][j]=0; 12 for(k=0;k<i;k++) 13 if(a[k][j]==0)a[i][j]=1; 14 for(k=0;k<j;k++) 15 if(a[i][k]==0)a[i][j]=1; 16 for(k=1;k<=min(i,j);k++) 17 if(a[i-k][j-k]==0)a[i][j]=1; 18 } 19 } 20 for(i=0;i<20;i++){ 21 for(j=0;j<20;j++) 22 printf("%d ",a[i][j]); 23 printf(" "); 24 } 25 }
输出前20组数据
我们可以发现这几种情况是输的
1 2
3 5
4 7
6 10 可以发现规律为 a=(int)(b-a)(aqrt(5)+1)/2 我也不知道规律怎么得到这个公式的
输出为1的情况 我们只需要让状态转为必败的状态就可以了
int t=(b-a)*(sqrt(5)+1)/2;
if(t<a) 假设 bb=b-(a-t) 及证明 t 和bb满足必败的条件、、
(bb+t-a-t)*(sqrt(5)+1)/2=(b-a)*(sqrt(5)+1)/2=t;
并且这种情况属于[x-k,y-k]这种 所以我们可以先判断
其他的两种自己看代码想 不想解释了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cctype> 5 #include<cmath> 6 #include<cstring> 7 #include<map> 8 #include<stack> 9 #include<set> 10 #include<vector> 11 #include<algorithm> 12 #include<string.h> 13 typedef long long ll; 14 typedef unsigned long long LL; 15 using namespace std; 16 const int INF=0x3f3f3f3f; 17 const double eps=0.0000000001; 18 const int N=500000+10; 19 const int MAX=1000+10; 20 int main(){ 21 int n,m; 22 while(scanf("%d%d",&n,&m)!=EOF){ 23 if(n==0&&m==0)break; 24 double b=(sqrt(5.0)+1)/2; 25 if(n==(int)(b*(m-n))){ 26 cout<<0<<endl; 27 continue; 28 } 29 cout<<1<<endl; 30 int t=(int)(m-n)*b; 31 if(t<n)cout<<t<<" "<<t+m-n<<endl; 32 for(int i=0;i<=m;i++){ 33 int x=m-i; 34 if(x>n&&(int)(b*(x-n))==x)cout<<x<<" "<<n<<endl; 35 else if(x<n&&(int)(b*(n-x))==x){ 36 cout<<x<<" "<<n<<endl; 37 } 38 } 39 } 40 }