博弈论之数学理论学习笔记

前言

学习来源:[学习笔记] (博弈论)Nim游戏和SG函数_nim博弈-CSDN博客

后面二、三有完全转载情况,主要是迫不及待去刷题了。

一、sg函数:

mex:获取不属于该集合的最小非负整数。

例如:mex{} = 0(空集合)mex{0,1,2,4} = 3; mex{2,4} = 0;

没有0的集合mex函数值为 0, 有0的集合mex函数值为非0.

有向无环图:x为当前局面也就是顶点。 y为x的后继也就是x指向y顶点,y也就是x的下一个局面。

sg(x) = mex{sg(y)| y为x的后继),要想建立sg函数,就需要知道sg的最深层sg值,也就是最后一个无后继顶点。

1.取石子游戏

一堆石头,有n个,每次可以的数集合{1,3,4}即step[] = {1,3,4},  求其sg值?

首先,sg[0] = 0; 也是游戏终点顶点x = 0处。 

因为sg(x) = mex{sg(y) | y是x的后继) 想要建立sg函数,首先求出sg(1),从0递推到n。这是sg函数的递归关系,也就有向无环图的前驱后继关系,x是前驱,y是后继。

把原游戏分解成多个独立的子游戏,则原函数sg函数是所有子游戏的sg函数值的异或

sg(G) = sg(G1)^sg(G2)^……^sg(Gn).

分别考虑每一个子游戏,计算其sg值

(1)可选步数step集合1-m连续整数,直接取模SG(x) = x%(m+1)

(2)可选步数step集合任意步数, SG(x) = x

(3)可选一系列不连续,用模板计算,上面那个表格,下面是代码打表和dfs建立sg

2.sg函数建立

核心是搜索遍历

①打表

核心思想:

总结:sg(x) = mex{sg(y)| y是x的后继}: 也就是满足递推关系,从最底层顶点可以递推出sg(x),最底层sg[0] = 0;

(1)从1 -> x 每一个局面遍历

(2)标记每一个局面的子局面sg函数值

(3)获取每一个局面的当前局面sg函数值:遍历:未标记的sg值,(不属于子局面的sg值最小非负整数)

代码

step 的排序是防止在遍历每一种子局面时出现局面遗漏

for(int j = 1; step[j] <= i; j ++) 如果,step = { 1,5,3} 而i 只搜索到 4,则step只能时{1} 本应该是{1,4} 两个进入子局面的选择。

int step[N],sg[N]; // 步数规则,某一局面的sg(x)函数值
bool vis[N]; //用于标记x的下一个局面的sg(y)函数值

void getSG(int x) {
	sort(f+1,f+1+n);
	memset(sg,0,sizeof sg) ;
	for(int i = 1; i <= x; i ++) {
		//遍历每一种局面,从底部开始递推
		memset(vis,0,sizeof vis); //初始化当前局面的子局面sg标记为0 
		for(int j = 1; step[j]<=i; j ++) { 
			//搜索每一种可选步数进入子局面 
			vis[sg[i-step[j]]] = 1;//标记子局面sg(y)值; 
		}
		//求当前局面sg函数值:遍历子局面
		for(int j = 0; j <=x; j ++) {
			if(vis[j] == 0) {
				//不属于子局面的最小非负整数(未标记)
				sg[i] = j; break;
			}
		}
	}
} 

②dfs

核心思想

总结:搜索当前局面的每一种子局面可能,sg(x) = mex{sg(y)| y是x的后继}

(1)递归出口x = 0;sg[0] = 0;

(2)遍历搜索每一种可能step可能选择,进入dfs进入子局面

(2)标记当前局面的子局面sg(y)值

(4)获取:当前局面sg(x)函数值搜索未标记也就是非子局面的最小sg值

代码

sg初始化为-1.不为-1,说明搜索到了sg[0]=0;0之后不会再有局面了,也就是游戏结束了。

sg[] 为x 对应的sg函数值,在所有堆中也是一样的

int step[N],sg[N], n; // n是step集合大小
bool vis[N];

int SG_dfs(int x) {
	if(sg[x]!=-1) return sg[x]; 
	//递归出口
	memset(vis,0,sizeof vis);//将当前局面x的子局面sg(y)初始化0
	for(int i = 0; i < n; i ++) {
		//遍历每一种step选择,dfs子局面
		if(step[i]<=x) {
			SG_dfs(x-step[i]); //进入子局面选择
			vis[sg[x-step[i]]]=1;// 标记子局面sg(y) 
		} 
	} 
	//获取当前局面sg值,搜索未标记的局面,非子局面集合的最小局面sg值 
	int i = 0; //从最小0开始遍历
	while(1) {
		if(!vis[i]) // 最小未标记子局面
		 	return sg[x] = i; // 返回当前局面sg(x)函数值 
		i ++; 
	} 
} 

二、ICG游戏公平组合游戏

今天我们要认识一对新朋友,Alice与Bob。
Alice与Bob总是在进行各种各样的比试,今天他们在玩一个取石子的游戏。
在这个游戏中,Alice和Bob放置了N堆不同的石子,编号1..N,第i堆中有Ai个石子。
每一次行动,Alice和Bob可以选择从一堆石子中取出任意数量的石子。至少取1颗,至多取出这一堆剩下的所有石子。

假设每一轮游戏都是Alice先行动,请你判断在给定的情况下,如果双方都足够聪明,谁会获得胜利?

讨论
这是一个古老而又经典的博弈问题:Nim游戏。

Nim游戏是经典的公平组合游戏(ICG)

对于ICG游戏我们有如下定义: 根据某种操作规则,使一方无法移动进入下一个局面。

  • 两名选手
  • 两名选手轮流行动,每一次行动可以在有限合法操作集合中选择一个
  • 游戏的任何一种可能的局面(position),合法操作集合只取决于这个局面本身,不取决于轮到哪名选手操作、以前的任何操作、骰子的点数或者其它因素;局面的改变称为“移动”(move)
  • 如果轮到某名选手移动,且这个局面的合法的移动集合为空(也就是说此时无法进行移动),则这名选手负

对于第三条,我们有更进一步的定义Position,我们将Position分为两类:

  1. P-position:在当前的局面下,先手必败
  2. N-position:在当前的局面下,先手必胜

它们有如下性质:

  1. 合法操作集合为空的局面是P-position
  2. 可以移动到P-position的局面是N-position
  3. 所有移动都只能到N-position的局面是P-position

算法实现
取子游戏算法实现——

步骤1:将所有终结位置标记为必败点(P点);
步骤2: 将所有一步操作能进入必败点(P点)的位置标记为必胜点(N点)
步骤3:如果从某个点开始的所有一步操作都只能进入必胜点(N点) ,则将该点标记为必败点(P点) ;
步骤4: 如果在步骤3未能找到新的必败(P点),则算法终止;否则,返回到步骤2。

在这个游戏中,我们已经知道A[] = {0,0,…,0}的局面是P局面,那么我们可以通过反向枚举来推导出所有的可能局面,总共的状态数量为A1∗A2∗…∗AN。并且每一次的状态转移很多。
虽然耗时巨大,但确实是一个可行方法。

当然,我们这里会讲这个题目就说明肯定没那么复杂。没错,对于这个游戏有一个非常神奇的结论:

对于一个局面,当且仅当A1 xor A2 xor … xor AN =0时,该局面为P局面。

如何证明这个结论呢?

这里写图片描述

三、ICG游戏,sg函数与nim游戏的联系

SG函数与Nim游戏的联系?
  如果对于一个游戏,它是ICG。那么我们可以发现,对于此游戏的一种局面,ICG上的多个sg函数的值,如果看做多个石堆的话,就相当于一个nim游戏!我们来一步步推导:

首先来个引理,s≥sg(x)s≥sg(x),这个用归纳法证,应该说简单。
如果当前局面,所有sg函数的值都是零,先手必输。

分类讨论一下。

如果当前局面上的所有棋子都不能走了,显然它们的sg函数值都是零,那么先手必输。

如果还有棋子能走,我们可以选一个棋子走一步,那么这个棋子的sg函数值就会变成非零。非零说明什么,说明当前棋子所在结点的孩子结点一定有一个sg函数值为零,那对手只要将棋走到那个结点就行了。然后局面就又变成了原来的。
前面那个其实相当于nim游戏的终止局面。

那普通局面就相当于有sg函数的值不为零。

还是分类讨论。

如果现在对手走,sg值异或和为零(注意是异或和),他会选一个石子,然后把这个石子放到它的孩子结点上。sg值有可能增加,也有可能减少。只要sg值增加,你就把它还原回来(根据sg函数的定义,好好思考一下!),那么sg函数总有不能增加的一天,因为第一条的引理。这就相当于sg值只能减少!那这不是一个nim游戏吗?根据nim游戏里面的证明,你一定可以找到一个数,找一个石子堆,减去这个数以后,异或和还是零。最终对手就会被逼迫到第二条的局面上,然后它就输了。反之如果异或和不为零,你一定输!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值