ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

公平组合游戏

2022-07-13 13:00:10  阅读:209  来源: 互联网

标签:ch 游戏 组合 Nim 公平 position oplus SG


目录

公平组合游戏

\(Nim\) 游戏

参考

概述与解法

\(Nim\) 游戏是 \(ICG(Impartial\ Combinatorial\ Games)\)

满足下列条件的游戏才算 \(ICG\) :

  1. 两个人
  2. 两个人交替对游戏进行移动,每次一步,选手可以在(一般而言)有限的合法移动集合中任选一种进行移动
  3. 对于游戏的任何一种可能的局面,合法的移动集合只取决于这个局面本身,不取决于轮到哪名选手操作、以前的任何操作、骰子的点数或者其它什么因素
  4. 如果轮到某名选手移动,且这个局面的合法的移动集合为空(无法移动),则这名选手 \(lose\) 。(根据这个定义,很多日常的游戏并非 \(ICG\))

满足上述条件的游戏才可以使用之后叙述的 \(Nim\) 游戏的解法来解决

\(Nim\) 游戏及解法

通常的\(Nim\) 游戏的定义是这样的:有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判\(lose\)(因为他此刻没有任何合法的移动)。

定义 \(P-position\) 和 \(N-position\) ,其中P代表 \(Previous\),\(N\) 代表 \(Next\)

直观的说,上一次 \(move\) 的人有必胜策略的局面是 \(P-position\),也就是“后手可保证必胜”或者“先手必败”,现在轮到 \(move\) 的人有必胜策略的局面是 \(N-position\),也就是“先手可保证必胜”

更严谨的定义是:1.无法进行任何移动的局面(也就是 \(terminal\ position\))是\(P-position\);2.可以移动到\(P-position\) 的局面是 \(N-position\);3.所有移动都导致\(N-position\)的局面是\(P-position\)。

\(Nim\) 游戏的结论:若是对于一个游戏局面 \(a_{1\sim n}\),它是 \(P-postion\) 当且仅当 \(a_1\oplus a_2\oplus \cdots \oplus a_n=0\)

这个证明也显然,若是满足 \(a_1\oplus a_2\oplus \cdots \oplus a_n=0\) ,则对于 \(a_{1\sim n}\) 其所有二进制位上的 \(1\) 有偶数个

也就是如果之后先手取一个那么后手就取对应的一个,最后总是先手的取不到

这样先手就输了

有向图游戏与 \(SG\) 函数

参考

概述

大部分公平组合游戏都可以转换为有向图游戏,即:

  • 在一个有向无环图中,只有一个起点,上面有一个棋子,两个玩家轮流沿着有向边推动棋子,不能走的玩家判 \(lose\)。

我们定义 \(mex(S)\) 函数:

\[mex(S)=\min\{x\}(x\in N,x\notin S) \]

如:\(mex\{1,2,3\}=0,mex\{0,1,3\}=2\)

对于状态 \(x\) 和它所有的 \(k\) 个后继状态 \(y_{1\sim k}\),定义其 \(SG\) 函数:

\[SG(x)=mex\{SG(y_1),SG(y_2)\cdots SG(y_k)\} \]

而对于有 \(n\) 个有向图组成的组合游戏,设其起点分别为 \(s_{1\sim n}\) ,则有定理:

当且仅当 \(SG(s_1)\oplus SG(s_2)\oplus \cdots \oplus SG(s_n)\neq 0\) 时先手必胜,同时,这是这一个组合游戏的游戏状态的 \(SG\) 值。

这一定理被称作 \(Sprague-Grundy(SG)\) 定理

可以把 \(SG\) 类比 \(Nim\) 来理解

而 \(Nim\) 游戏可以转化为一个有向图游戏用 \(SG\) 定理求解

习题

P2197 【模板】nim 游戏

#include<bits/stdc++.h>
using namespace std;

#define re register

inline int read(){
	re int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

signed main(){
	re int T=read();
	while(T--){
		re int n=read(),ans=0;
		for(re int i=1;i<=n;++i) ans^=read();
		puts(ans?"Yes":"No");
	}
}

P1247 取火柴游戏

思路

这题多了一个输出方案

按照 \(Nim\) 游戏的解法,我们先求出 \(chk=a_1\oplus a_2\oplus \cdots \oplus a_n\)

若 \(chk=0\),即 \(P-position\),则先手必输

否则,我们考虑让电脑在我们取完第一次之后变为 \(P-positon\)

也就是让某一个 \(a_i\) 变为 \(chk\oplus a_i\),这样就可以达到目的

判断一下 \(chk\oplus a_i\) 是否大于等于 \(a_i\) 就行 (不能不取,也不能拿负数个)

#include<bits/stdc++.h>
using namespace std;

const int N=5e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n;
int a[N];

signed main(){
	n=read();
	int chk=0;
	for(int i=1;i<=n;++i){
		a[i]=read();
		chk^=a[i];
	}
	if(!chk){
		puts("lose");
		return 0;
	}
	for(int i=1;i<=n;++i){
		if((chk^a[i])>=a[i]) continue;
		printf("%d %d\n",a[i]-(chk^a[i]),i);
		a[i]=chk^a[i];
		for(int j=1;j<=n;++j) printf("%d ",a[j]);
		break;
	}
}

标签:ch,游戏,组合,Nim,公平,position,oplus,SG
来源: https://www.cnblogs.com/into-qwq/p/16473469.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有