从SG函数浅谈解决博弈问题的通法

时间:2022-09-14 18:51:23

基于笔者之前对于几种二元零和博弈游戏的介绍,这里将其思想进行简单的提炼,并引出解决这类二元零和博弈游戏的强大工具——SG函数。

其实对于博弈游戏如Bash、Nim等基本类型,异或一些比较高级的棋类游戏例如井字棋、中国象棋、华容道等,可以说它们是同质的。

我们先从比较高的角度来看待如何得到博弈当中最优的策略,这其实也是笔者认为解决简单的二元零和博弈、理解SG函数和写棋类AI关键所在。博弈是一个大量状态之间进行转移的过程,我们将每种状态视为一个节点,这种转移关系视为一种有向边,那么我们容易构建起博弈树(在SG函数中我们常称“游戏树”),我们是从结局(即叶节点,因为它的胜负态一目了然)往前搜索,然后逆着正常决策的过程,标记每种局面的胜负态,然后来帮助我们在按照正常决策顺序的时候,选出最优策略。对于华容道、五子棋、井字棋这类游戏,需要根据当前出现的局面,然后模拟出接下来可能出现的所有情况,然后评估棋局并回溯回来标记出最优策略。同样对于二元零和博弈,也是相同的道理。只不过二元零和博弈非常简单,其胜负态(我们用N标记面临当前局面的人有必胜策略,P是必败策略)常常会呈现出规律化的分布(这就是很多人常说的“找规律”,但是它没有体现“找规律”这种方法和博弈本身的关系),因此我们能够设计线性的算法来判断其胜负态。

我们来举个例子来理解一下这个过程:

ex1:给出一个nxm棋盘,将棋子从(1,m)开始移动,要求只能向左、下、左下移动,不能移动棋子的人输,请问分析这个游戏的必胜态分布。(Problem source :hdu 2147 )

分析:对于这个问题,我们按照上面我们给出解决博弈问题的通法,从结局开始分析。

对于这个矩阵(显然棋局可以看成矩阵),我们从(n,1)这个状态开始构建NP分布图,以4x4的矩阵为例,我们容易得到如下的NP分布图。

N N N N

P N P  N

N N N N

P N P  N

规律就一目了然了。

那么下面我们通过一个具体的问题来引出解决这一类二元零和博弈问题的通解——sg函数。其实从本质上讲,它就是一个打NP表的有力工具。

ex2:给出三个石子堆的数目m、n、p,两个游戏玩家每次只能拿取斐波那契数个石子,最终没有石子取得人输,如何分析胜负态的分布?(Problem source : hdu 1848)

有nim博弈基础读者会注意到,这其实是单堆nim的推广形式,既然是推广形式,就应该使用推广方法,即sg函数。

上文提到,任何博弈都可以看成多个状态之间的转移,我们将每种状态视为一个顶点,而状态之间的转移视为点与点的有向边,这样我们容易建立起无环有向树,也就是我们常说的博弈树或者是状态树,而我们判断胜负态分布的关键就是从胜负态显然的叶节点开始,然后往根部构造sg函数。

整体的思路明了了,我们如何具体的计算sg函数呢?

这里定义一个运算符mex,对于整数集合mex(S),mex(S)的值是S集合中没有出现的最小负整数,那么对于sg(x),它记录着状态参数x(玩家当前面临单堆石子的剩余数)对应的胜负态,对于它的计算,有如下递推定义:

sg(x) = mex({sg(y)|y∈son(x)}),其中son(x)表示状态树中状态参量x的儿子所有节点构成的集合。

递推计算式给出的貌似有些唐突,我们从叶节点开始尝试模拟,对于x = 0的叶节点,按照上述定义,显然有sg[0] = 0.它其实对应着P态。而对于它的父节点x1,我们根据递推定义,sg(x1)必然不为0,也很容易理解它对应着N态,结合二元零和博弈胜负态的交替规律(这个规律很多资料中视为定理进行表述,对于理解整个决策过程非常重要),我们能够得到整个博弈树顶点的权值,即sg函数。

我们还会得到结论,对于状态x,sg(x) = 0,面临这个状态参量x的游戏者必败。(可见很多资料往往“先手必胜”的说法并不准确。)

当sg(x) != 0,面临这个状态参量x的游戏者必胜。

其实可能有读者已经会疑惑了,这里sg(x)储存的值其实只有两种形态(0和非0),那么我们储存那些非零的数还有什么意义呢?

刚好这与我们下面要解决的问题是呼应的。

上文讨论了单堆取石子游戏的推广形式如何用sg函数来解决,那么对于ex2中的三堆含m、n、p个的石子(称为多个sg函数组合起来的组合游戏),基于对运算符mex和sg函数自身内涵的理解,面对sg(m) = k,我们可将其视为从含k个石子堆拿出任意数量的游戏操作(有人可能会质疑是否会面临sg(m) = mex({0,1,2,...,k,k+2})这种使得转化不等价的局面,其实可以实践一下,对于状态m是否会出现sg(y) = k + 2)。那么取石子游戏的推广类型就利用sg函数得到了完美解决.

简单的参考代码如下:

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = ;
int sg[maxn] , flag[maxn];
int f[]; void get_sg(int n)
{
sg[] = ;
for(int i = ;i <= n;i++)
{ memset(flag , , sizeof(flag));
for(int j = ;i - f[j] >= ;j++)
flag[sg[i - f[j]]] = ;
for(int k = ;;k++)
{
if(flag[k] == )
{
sg[i] = k;
break;
}
}
}
}
int main()
{
f[] = , f[] = ;
for(int i = ;i <= ;i++)
{
f[i] = f[i-] + f[i-];
// printf("%d\n",f[i]);
}
get_sg();
int m , n , p;
while(scanf("%d%d%d",&m,&n,&p) != EOF)
{
if(n == || m == || p == )
break;
if((sg[m]^sg[n]^sg[p]) == ) //注意位运算和==运算符的优先级
printf("Nacci\n");
else
printf("Fibo\n");
}
}

从SG函数浅谈解决博弈问题的通法的更多相关文章

  1. hdu 1847&lpar;SG函数,巴什博弈&rpar;

    Good Luck in CET-4 Everybody! Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  2. 从 A&sol;Looper&colon; Could not create epoll instance&period; errno&equals;24 错误浅谈解决各种 bug 的思路

    今天代码写着写着就莫名闪退了,手机也没有“程序停止运行”的提示,logcat也没有看到蓝色的调用栈log,这样的闪退最是蛋疼了,还好必现.复现几次之后,终于从logcat中看到了一行可疑的log: A ...

  3. Javascript-回调函数浅谈

    回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而是在特定 ...

  4. C&num; eval&lpar;&rpar;函数浅谈

    <%# Bind("Subject") %> //绑定字段 <%# Container.DataItemIndex + 1%> //实现自动编号<%# ...

  5. 继承虚函数浅谈 c&plus;&plus; 类,继承类,有虚函数的类,虚拟继承的类的内存布局,使用vs2010打印布局结果。

    本文笔者在青岛逛街的时候突然想到的...最近就有想写几篇关于继承虚函数的笔记,所以回家到之后就奋笔疾书的写出来发布了 应用sizeof函数求类巨细这个问题在很多面试,口试题中很轻易考,而涉及到类的时候 ...

  6. Sql Server存储过程和函数浅谈

    今天给大家总结一下sql server中的存储过程和函数.本人是小白,里面内容比较初级,大神不喜勿喷 自行飘过就是.. 首先给大家简单列出sql server中的流控制语句,后面会用到的^_^ sql ...

  7. 从Java继承类的重名static函数浅谈解析调用与分派

    在java中,static成员函数是否可以被重写呢? 结论是,你可以在子类中重写一个static函数,但是这个函数并不能像正常的非static函数那样运行. 也就是说,虽然你可以定义一个重写函数,但是 ...

  8. Hash函数浅谈

    Hash函数是指把一个大范围映射到一个小范围.把大范围映射到一个小范围的目的往往是为了节省空间,使得数据容易保存. 除此以外,Hash函数往往应用于查找上.所以,在考虑使用Hash函数之前,需要明白它 ...

  9. 【转】博弈问题及SG函数(真的很经典)

    博弈问题若你想仔细学习博弈论,我强烈推荐加利福尼亚大学的Thomas S. Ferguson教授精心撰写并免费提供的这份教材,它使我受益太多.(如果你的英文水平不足以阅读它,我只能说,恐怕你还没到需要 ...

随机推荐

  1. 跟我一起数据挖掘(22)——spark入门

    Spark简介 Spark是UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用的并行,Spark,拥有Hadoop MapReduce所具有的优点:但不同于MapR ...

  2. (原创)mybatis学习一,夯实基础

    一,what?(是什么) MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可 ...

  3. ecshop 签名

    先从index.php主页开始 页面关键字 {$keywords } 页面标题 {$page_title} 产品分类 父分类列表 {foreach from=$categories item=cat ...

  4. Editthiscookie

    Editthiscookie,联调,.s环境加cookie才能访问.laravel

  5. Android开发之ProgressDialog在独立Thread线程中更新进度

    简单的需求:在一个工作Thread中更新进度对话框ProgressDialog 遇到的问题: 1,创建需要Context,这个需要传进来 2,Thread中不能创建ProgressDialog,否则需 ...

  6. HTML中的&lt&semi;select&gt&semi;标签如何设置默认选中的选项

    方法有两种. 第一种通过<select>的属性来设置选中项,此方法可以在动态语言如php在后台根据需要控制输出结果. 1 2 3 4 5 < select  id =  " ...

  7. 如何制作网页小动画?——gif or png

    一.场景与动画 为了拉动网站氛围,或者吸引用户浏览焦点,需要使用一些小动画.这种动画不是(gif)单纯的重复,而是需要需要一些控制和交互,比如在动画完成后打开一个对话框.动画有几个基本要素(时间控制, ...

  8. qt5集成libcurl实现tftp和ftp的方法一:搭建环境(五篇文章)

    最近使用QT5做一个软件,要求实现tftp和ftp文件传输,使用QT5开发好UI界面等功能,突然发现QT5不直接提供tftp和ftp支持,无奈之下只好找第三方库来间接实现,根据网友的介绍,libcur ...

  9. db&period;properties是干什么用的

    连接池配置文件db.properties是java中采用数据库连接池技术完成应用对数据库的操作的配置文件信息的文件.具体配置项目如下:drivers=com.microsoft.sqlserver.j ...

  10. 8 -- 深入使用Spring -- 6&period;&period;&period; Spring的事务

    8.6 Spring 的事务 8.6.1 Spring支持的事务策略 8.6.2 使用XML Schema配置事务策略 8.6.3 使用@Transactional 参考1. 啦啦啦 我早就肯定我的身 ...