Nim游戏(博弈论)
今天我想跟大家分享的是一个博弈论游戏,我觉得这种类型的题目第一次遇到还是很有思维含量的,里面着重介绍了一些难懂的点,不说废话了,直接引入正题啦
Nim游戏
给定 n 堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 n。
第二行包含 n 个数字,其中第 ii 个数字表示第 ii 堆石子的数量。
输出格式
如果先手方必胜,则输出 Yes
。
否则,输出 No
。
数据范围
1≤n≤10^5,
1≤每堆石子数≤10^9
输入样例:
2
2 3
输出样例:
Yes
先说下结论吧,然后我会给出证明
当这n个数的异或结果为0时,先手必败,否则先手必胜(前提是他们都足够聪明哈哈)
证明:
不难发现,当最后一个玩家拿走最后的石子后,所有的石子都被拿完了,那么此时所有石子的异或值肯定为0;
我们假设初始值满足所有石子的异或和不为0,我们证明先手能够做到将所有石子的异或值变为0:
假设a1^a2^……^an=x!=0
我们假设x的二进制位串上1所在的最高位为k,那么x1~xn中至少有一个数第k位也为1,不妨假设这堆石子个数为aj,
先来证明一下aj^x<aj
不难发现,aj中第k位由1变成了0,而第k位之上的数都没有发生改变,故
aj^x<aj显然成立
那我们就将aj这堆石子数目取至aj^x;则a1^a2^……^aj^x^……^an=x^x=0;
所以结论成立
下面我们证明一下当原先石子异或值为0,我们怎样操作都无法保证异或值仍然为0
假设
a1^a2^……^an=0,我们将aj取至m(aj>m)仍然有
a1^a2^……^m^……^an=0成立,我们将两个式子异或在一起可得
aj^m=0,又因为aj!=x,所以这是不可能的,故原假设不成立,证毕!
通过这两个结论的证明,我们可以发现一个玩家可以将石子异或值由非0变为0,所以只要一个玩家一直能保证石子异或值为0,那么他就会必胜!
代码比较简单,重点是要理清思路
#include<bits/stdc++.h> using namespace std; int main() { int n; cin>>n; int ans=0,t; while(n--) { cin>>t; ans^=t; } if(ans) printf("Yes"); else printf("No"); return 0; }
希望大家能够喜欢!
心中所爱,山海可平