标签:cin 尼姆博弈 space 比较 break 输出 操作 输入 ret
这道题我题意都看了好一会,原谅我基础不扎实。
题意:从输入的数据中选择其中一个,分成两个数,将分成的第二个数与其他数相异或(“异或”运算符(^)相同为0,不同为1。0^0=0,1^0=1,1^1=0),若最终结果为1则输出Yes。将所有石堆的数目,进行异或操作,如果结果为0,则先取者负。如果不为0,则先取者胜,且将异或结果与各堆数目进行异或,结果比原来的数少,则可把原来数目取为异或结呆,使对方处于必败态
看了别人的解题思路:本题和前面写的那题思路是一样的。求出在第i堆取完石子后应该剩下多少个 与其它堆相异或等于0,这是留给对手的是必败态,所以只要求出其它堆的异或值就好了,因为两个相同的数异或以后才是0,。注意:大于10000的数据输入要用scanf啊,不然会超时。
尼姆博弈基本思想:
两人从n堆物品中取任意个,先取完者胜。
即将n堆物品的数量异或,得到的值如果为0,则先手败,反之先手胜。
如果要求先手在胜的条件下,到奇异局势的方法数,则判断异或的值与每一堆原值异或后(结果应该表示该堆没有参加异或时的异或值)与原值比较大小,
如果小于,则方法数加一。且对应的方法后,该堆的数目应变为异或的值与每一堆原值异或的值。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int main()
{
int n,m[200000],k,i,s;//n是石子的堆数,数组m存储的是每堆石子的个数
while(scanf("%d",&n)!=EOF)
{
if(!n)
break;
s=0;
for(i=0;i<n;i++)
{
cin>>m[i];//根据NIMM博弈的推理策略,应该对每一堆的石子进行异或运算
s=s^m[i];//异或操作
}
if(!s)//s==0(必败态)先取者总是遇见非奇异局势(第一次就是非奇异局势)
{
printf("No\n");
}
else
{
printf("Yes\n");
for(i=0;i<n;i++)
{
k=s^m[i];
if(k<m[i])
printf("%d %d\n",m[i],k);
}
}
}
return 1;
}
标签:cin 尼姆博弈 space 比较 break 输出 操作 输入 ret
原文地址:http://www.cnblogs.com/Emilylice/p/7701110.html