做hdu2176的时候就准备做这题,发现不会。今天看着解题报告,做的。囧。记忆力实在是差。看来还是得遵守记忆曲线。温故而知新。
理论:(来自:http://www.wutianqi.com/?p=1081)
下面解题报告来自:http://blog.csdn.net/liwen_7/article/details/7937113
那么任给一个局势(a,b),怎样判断它是不是奇异局势呢?我们有如下公式:
对于某个局势(a,b) ,b>=a
差值k=b-a
对于某个确定的k
有唯一的奇异局势(必败点) (a_k,b_k) 其中a_k=k*(1+sqrt(5))/2 b_k=a_k+k
如果a,b是奇异局势 则输出0
不是的话输出1(通过某种操作可以获胜)
已知a,b
操作分5种
1.a==b
同时减去a 得到0,0
2.a==a_k b>b_k
b -(b-b_k)
3.a==a_k b<b_k
同时拿走a_k-a_(b-a_k)
得到 a_(b-a_k) a_(b-a_k) + b-a_k
4.a>a_k b==b_k
从a中拿走 a-a_k
5.a<a_k b==b_k
5.1 a==a_ j (j<k)
b-(b-b_ j)
得到 a_ j b_ j
5.2 a==b_ j (j<k)
b-(b-a_ j)
得到 b_ j a_ j
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<string.h> #include<math.h> using namespace std; int main() { int n, m; int k; double x=(1+sqrt(5.0))/2; while(scanf("%d%d",&n,&m)!=EOF && n+m) { if(n>m) //如果 n > m,根据奇异局势应该要a<b { n^=m; //通过三个异或 交换n、m m^=n; n^=m; } k=m-n; //显然,遇到奇异局势的人一定会输。 if((int)(k*x)==n) printf("0\n"); //因为奇异局势变成非奇异局势后,下一个人一定可以将局势 //再次变成奇异局势,所以一定还是第一次遇到奇异局势的人遇到奇异局势,则他定输 else { printf("1\n");//碰到非奇异局势,将其变成奇异局势,可能有两种变法。 for(int i=1;i<=n;i++)//①:同时从两堆中拿相同数目的石子。 { int a=n-i , b=m-i; k=b-a; //cout<<"a= "<<a<<" b= "<<b<<" "<<x<<endl; if((int)(k*x)==a) printf("%d %d\n",a, b); }//cout<<"111111111111"<<endl; for(int i=m-1;i>=0;i--)//②:从一堆中取。 { int a=n , b=i; if(a > b) //同理,保持奇异局势中 a < b { a^=b; b^=a; a^=b; } k=b-a; if((int)(k*x)==a) printf("%d %d\n",a , b); }//cout<<"22222222222222"<<endl; } } return 0; }