简单博弈论

简单博弈论

Nim游戏

Nim游戏满足以下三个条件:
(1)两名玩家交替行动
(2)游戏过程中,可以执行的的行动和轮到哪位玩家没有关系
(3)不能行动的玩家判负
比如围棋就不是一种Nim游戏,因为围棋有黑白两子不满足(2),围棋判断输赢规则较为复杂不符合(3)。下面的取石子游戏就是一个Nim游戏:给定n堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
例如:有两堆石子,第一堆有2个,第二堆有3个,先手必胜。
操作步骤:

  1. 先手从第二堆拿走1个,此时第一堆和第二堆数目相同
  2. 无论后手怎么拿,先手都在另外一堆石子中取走相同数量的石子即可。
  • 两个概念
    必胜状态:即经过某一个操作后留给另一个玩家的是一个必败状态,则对于先手玩家来说就是一个必胜状态,即先手可以走到一个必败状态。
    必败状态:即无论怎么操作都必定会走到一个必胜状态,则对于先手玩家来说是一个必败状态,即先手必定走到一个必胜状态。
  • 解决方法和数学证明
    假设这n堆石子分别为a1,a2,a3an个,那么当a1 xor a2 xor a3xor an=0时为先手必败,a1,a2,a3an个,那么当a1 xor a2 xor a3xor an0时为先手必胜。(xor是异或运算)
    证明:首先当每堆石子数量都为0时有:a1 xor a2 xor a3xor an=0此时为终止状态,先手必败。当a1 xor a2 xor a3xor an=x0时,我们设x的二进制数为1的最高位是第k位,显然有a1~an中至少有一个数的二进制数的第k位为1,不妨设这个数为ai,则ai xor x<ai[^异或计算],那么就可以保证从第i堆石子中取ai(ai xor x)有意义,设取了以后第i堆剩下的石子个数为a=ai(ai(ai xor x))=ai xor x,则取后各堆石子异或为:a1 xor a2 xor a3xor a xor an=a1 xor a2 xor a3xor ai xor x xor an=x xor x=0所以对于任一个各石堆个数异或值不为0的状态,我们都可以取特定的石子让它变为异或值为0的状态,即此时状态为先手必胜。再证:首先当a1 xor a2 xor a3xor an=0此时为先手必败状态。这里我们可以用反证法,假设我们可以通过取一定的石子让它的异或值继续为0,即:
    不知道为什么,这下面的发不出来。

\begin{cases} a_1\space xor\space a_2\space xor\space a_3\dots xor\space a_n=0&(1)\\ a_1\space xor\space a_2\space xor\space a_3\dots xor\space a^{\prime}\dots\space xor\space a_n=0&(2) \end{cases} $$(1),(2)两边同时异或得$a_1\space xor\space a_2\space xor\space a_3\dots xor\space a_n\space xor\space a_1\space xor\space a_2\space xor\space a_3\dots xor\space a^{\prime}\dots\space xor\space a_n=0$这里除了$a_i$和$a^{\prime}$外其余都是成对得所以$a_1\space xor\space a_2\space xor\space a_3\dots xor\space a_n\space xor\space a_1\space xor\space a_2\space xor\space a_3\dots xor\space a^{\prime}\dots\space xor\space a_n=0\Longleftrightarrow a_i\space xor\space a^{\prime}=0\Longrightarrow a_i=a^{\prime}$,Nim游戏中每一次都必须进行操作所以$a_i\ne a^{\prime}$,与规则矛盾,所以当$a_1\space xor\space a_2\space xor\space a_3\dots xor\space a_n=0$此时为先手必败状态,证毕。 [^异或计算]:异或计算是不进位加法,例如$1\space xor\space3=001\space xor\space 011=010=2$,这里$a_i=00\underbrace{1\dots}_{k}$ 而$x=00\underbrace{1\dots}_{k}$二者异或第k位必定变为0则必定小于$a_i$ - 代码实现 ```c++ #include<iostream> using namespace std; int main() { int n; cin>>n; int res=0; for(int i=0;i<n;i++) { int x; scanf("%d",&x); res^=x; } if(res==0) { printf("No"); } else { printf("Yes"); } return 0; } ``` ## sg函数 - mex操作 mex操作是指求一个集合中未出现的最小自然数,例如mex(1,2,3)=0,mex(0,1,2,4,5)=3。 - sg函数定义 在一个有向图中,对于每个节点x,从x出发有k条边,分别能到$y_1,y_2,y_3\dots y_k$则$sg(x)=mex(sg(y_1),sg(y_2),sg(y_3)\dots sg(y_k))$,特别地,终点的sg值为0。一个图的sg值定义为起点的sg值 ![输入图片说明](/imgs/2023-07-12/gQTU7PPHq7u2MWcC.png) 容易看出sg函数有性质: (1):若sg(x)=k$\ne 0$,则x点能到达的点的sg值最大为k-1. (2):sg值为0的点走不到sg值为0的点 (3):sg值不为0的点一定能走到sg值为0的点 - 定理 在一个图中,若sg(s)=0,则先手必败,若sg(s)$\ne 0$,则先手必胜。 在n个图中,若$sg(s_1)\space xor\space sg(s_2)\space xor\space sg(s_3)\dots\space xor\space sg(s_n)=0$为先手必败,反之必胜,从sg函数的性质很容易能够理解。 - 代码实现 给定 n 堆石子以及一个由 k 个不同正整数构成的数字集合 S。 现在有两位玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数量必须包含于集合 S,最后无法进行操作的人视为失败。 问如果两人都采用最优策略,先手是否必胜。 ```c++ #include<iostream> #include<unordered_set> #include<cstring> using namespace std; const int N=1e5+10,M=110; int f[N],g[M],h[M]; int k,n; int sg(int x) { if(f[x]!=-1) { return f[x];//让每个值的sg值只算一遍 } unordered_set<int> s;//用哈希表来存储x点取后会变为哪些状态 for(int i=0;i<k;i++) { int sum=g[i]; if(x>=sum) { s.insert(sg(x-sum)); } } for(int i=0;;i++) { if(!s.count(i))//注意哈希表如果什么也没有插入,查询0也会返回不存在,for循环从0开始所以这里可以保证终点的sg值一定为0 { f[x]=i; return f[x]; } } } int main() { cin>>k; memset(f,-1,sizeof(f)); for(int i=0;i<k;i++) { scanf("%d",&g[i]); } cin>>n; for(int i=0;i<n;i++) { scanf("%d",&h[i]); } int res=0; for(int i=0;i<n;i++) { res^=sg(h[i]); } if(res==0) { printf("No"); } else { printf("Yes"); return 0; } } ```

posted @   Taco_gu  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示