其他分享
首页 > 其他分享> > 公平组合游戏

公平组合游戏

作者:互联网

目录

公平组合游戏

\(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\) 函数

参考

概述

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

我们定义 \(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