历届试题 高僧斗法
时间限制:1.0s 内存限制:256.0MB
问题描述
古时丧葬活动中经常请高僧做法事。仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。
节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示N级浮屠)。又有若干小和尚随机地“站”在某个台阶上。最高一级台阶必须站人,其它任意。(如图1所示)
两位参加游戏的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。两个小和尚也不能站在同一台阶,也不能向低级台阶移动。
两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。
对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。
输入格式
输入数据为一行用空格分开的N个整数,表示小和尚的位置。台阶序号从1算起,所以最后一个小和尚的位置即是台阶的总数。(N<100, 台阶总数<1000)
输出格式
输出为一行用空格分开的两个整数: A B, 表示把A位置的小和尚移动到B位置。若有多个解,输出A值较小的解,若无解则输出-1。
样例输入
1 5 9
样例输出
1 4
样例输入
1 5 8 10
样例输出
1 3
ps:将阶梯博弈转换为尼姆博弈。首先要清楚,对于n个和尚,我们究竟要取多少堆”石子”呢?(一堆石子数目等于两个和尚之间的阶梯位置之差)
举个例子,如图有三个和尚,间隔分别为3和5,那么我们只需要第一堆的石子就行(也就是3),为什么呢?因为和尚2移动多少距离和尚1也能移动相同的距离,所以这一堆‘’石子”就失去了意义,也就是说不是一对石子的石子没有意义(因为我们总能通过移动这一对的前一个石子来还原原有的距离)。(这里1和2是一对,3和4是一对【如果后面还有一个和尚4】)现在我们就这个图来模拟该游戏,我是先手,我把和尚1移动到和尚2的旁边(距离为0,相当于石子数为0),那么无论后手再怎么移动我总能通过移动和尚1来保持和他的距离不变。因此取每队和尚之间的石子去尼姆博弈就可以了。
#include<iostream>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int a[1004];
int total = 0;
while(cin>>a[total++]);
int b[1004];
for(int i = 1; i < total; i++)
b[i - 1] = a[i] - a[i - 1] - 1;
int ans = 0;
for(int i = 0; i < total - 2; i += 2) ans ^= b[i];
if(ans == 0)cout<<-1<<endl;
else{
for(int i = 0; i < total - 1; i++)
{//从第一个和尚开始枚举
int flag = 0;
for(int j = 1; j + a[i] < a[i+1]; j++)
{//第i个和尚移动j个台阶
b[i] -= j;
ans = 0;
if(i != 0) b[i-1] += j;//i处石子减少,i-1处石子增加,因为区间扩大
for(int k = 0; k < total - 2; k += 2) ans ^= b[k];
if(ans == 0){
flag = 1;
cout<<a[i]<<" "<<a[i] + j<<endl;
break;
}
//如果先手不能将必胜态转为必败态(转换后ans == 0),则回溯
b[i] += j;
if(i != 0) b[i-1] -= j;
}
if(flag)break;
}
}
return 0;
}