蓝桥杯 [高僧斗法] Nim博弈
题目链接:http://lx.lanqiao.cn/problem.page?gpid=T37
题目大意:有个阶梯,上面有些僧人,大师指挥他们。僧人只能向上走,并且不能站在一起或者超越高层的僧人。最高层的僧人不能动。在这些条件下,大师指挥他们任何一个(除了最高层的)走任意级台阶,当没有僧人能指挥时,游戏结束,遇到这种情况的大师告败。
关键思想:考虑到最低的僧人与最高的僧人相差台阶数是在不断减小的。移动一个僧人的时候,与上方的僧人距离减小,与下方的僧人距离增大。突发奇想出Nim博弈的模型{
不如从低到高,每两个僧人配对(无重复),他们之间的距离看作是石子数,然后进行nim博弈。
搬运justPassBy的博客中的解释
我们可以将人从前往后两两配对,在同一对人中,如果对手移动后一个人,你总能移动前一个相同的步数,
所以一对人的后一个人与后面一对人的前一个人有多少台阶是没有影响的。
所以只要考虑同一对人之间有多少台阶就行了,这样就转化为了Nim游戏。
如图: a与b配对, c与d配对 ,那么b与c之间的台阶是没有影响的,无论b怎么移动,a总能够移动相同的步数。
}
可以发现,我们这个Nim博弈和原始版本的Nim区别就在于有些缓冲的操作(不玩~玩嘛~不玩~玩嘛),而且石子数可以增加,但胜负条件是不变的,因为胜败格局的转移是双向的。
代码如下:
#include <iostream> #include <algorithm> using namespace std; const int N=1010; int main(){ int a[N],b[N],cnt1=0,cnt2=0; for(cnt=0;cin>>a[cnt];cnt++); sort(a,a+cnt); //输入似乎是有序的,可以不加 int XOR=0; //各个有效距离的异或 for(int i=0;i<cnt1-1;i++,cnt2++){ b[i]=a[i+1]-a[i]-1;//b[i]存储没两个点之间的距离,但有效的只有下标为偶数的距离 if(i%2==0)XOR^=b[i];//只对有效距离异或 } if(XOR==0)cout<<-1<<endl; else{ for(int i=0;i<cnt2;i+=2){//考虑每个有效距离 if((XOR^b[i])<b[i]){ //如果需要的距离小于有效距离 cout<<a[i]<<" "<<a[i]+b[i]-(XOR^b[i])<<endl;//移动左边的点 break; }else if((XOR^b[i])<=b[i]+b[i+1]){ //如果需要的距离大于有效距离但是可以向右扩展 cout<<a[i+1]<<" "<<a[i]+(XOR^b[i])+1<<endl;//移动右边的点 break; } } } return 0; }
边完善自己边认识自己