洛谷P2197 【模板】nim游戏
P2197 【模板】nim游戏
题目描述
甲,乙两个人玩 Nim
取石子游戏。
Nim
游戏的规则是这样的:地上有n
堆石子(每堆石子数量小于 \(10^4\)),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这n
堆石子的数量,他想知道是否存在先手必胜的策略。
输入格式
本题有多组测试数据。
第一行一个整数T(T \(\le\) 10),表示有T
组数据
接下来每两行是一组数据,第一行一个整数n
,表示有n
堆石子,n \(\le\) 10000。
第二行有n
个数,表示每一堆石子的数量.
输出格式
共T
行,如果对于这组数据存在先手必胜策略则输出 Yes
,否则输出 No
,每个单词一行。
输入输出样例
输入 1
2
2
1 1
2
1 0
输出 1
No
Yes
首先引入NIM
游戏这么一个定义
1、有两个玩家,轮流进行操作
2、是公平游戏。即面对同一局面两个玩家所能进行的操作是相同的。例如中国象棋不是公平游戏:因为面对同一个局面,红方只能移动红色棋子而不能移动黑方棋子,黑方同理。
3、一个玩家是输掉当且仅当他无法进行操作。例如如果是两个人轮流取石子的游戏,那么一个玩家输掉当且仅当他面前没有石子了,因为他下面无法进行取石子的操作。
一般的,Nim
游戏指两个玩家轮流在好几堆东西中取物品,不能隔堆取,无法操作判负。
因为是模板,那相对来说肯定是比较简单,那我们就不妨从最基础的开始讲起吧
NIM
游戏的来源如下
在一份资料上看到,这种游戏称为“拈(Nim
)”。据说,它源自中国,经由被贩卖到美洲的奴工们外传。辛苦的工人们,在工作闲暇之余,用石头玩游戏以排遣寂寞。后来流传到高级人士,则用便士(Pennies
),在酒吧柜台上玩。其中,最有名的玩法,是把十二枚便士放成3、4、5
三列,拿光铜板的人赢。后来,大家发现,先取的人只要在3
那列里取走2
枚,变成了1、4、5
,就能稳操胜券了,游戏也就变得无趣了。于是大家就增加列数,增加铜板的数量,这样就让人们有了毫无规律的感觉,不易于把握。
直到本世纪初,哈佛大学数学系副教授查理斯·莱昂纳德·包顿(Chales Leonard Bouton
)提出一篇极详尽的分析和证明,利用数的二进制表示法,解答了这个游戏的一般法则。 一般规则是规定拿光铜板的人赢。 它的变体是规定拿光铜板的人输,只要注意某种特殊形态(只有1
列不为1
),就可以了!
我们可以明显的看出这个问题是基于二进制下的
所以考虑一波位运算
发现我们可以观察到的神奇性质
就是说当最后所有都被取完了之后,所有0
的异或和是0
那么就考虑可不可以经过先手操作来达到最后使所有堆石子数目的异或和变为0
发现我们只要是每一次自己操作时将这些堆的异或和变成0
就能保证对手(即后手)在下一次操作时不会将答案变成0
,这个显然是正确的,就比如说,对手无论在对面怎么取也不会使得我们这些堆里面在异或和为0
的情况下不发生改变
但是我们也发现一个弊端,就是说如果一开始的初始状态的所有堆的石子数异或和就是0
的话,我们就会因为对手的鬼魅操作而变得没有机会将这些个堆的石子数异或和变为0
代码就显然比较简单了
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,n;
cin>>t;
while(t--)
{
cin>>n;
int ans=0,m;
for(int i=1;i<=n;i++)
{
cin>>m;
ans^=m;
}
if(ans)
puts("Yes");
else
puts("No");
}
return 0;
}
据各位学长(包括qbxt
的讲师)来说基本上80 Percent
的博弈论都可以转化为NIM
来求解,所以说NIM
还是比较重要的吧。