博弈论之SG函数

惯例先引入一些概念:(概念来自于网络)

有向图游戏:
给定一个有向无环图,图中有一个唯一的起点,在起点上放有一枚棋子。两名玩家交替地把这枚棋子沿有向边进行移动,每次可以移动一步,无法移动者判负。该游戏被称为有向图游戏。

任何一个公平组合游戏都可以转化为有向图游戏。具体方法是,把每个局面看成图中的一个节点,并且从每个局面向沿着合法行动能够到达的下一个局面连有向边。

Mex运算: 设S表示一个非负整数集合。定义mex(S)为求出不属于集合S的最小非负整数的运算,即: mex(S) = min{x},
x属于自然数,且x不属于S。

SG函数: 在有向图游戏中,对于每个节点x,设从x出发共有k条有向边,分别到达节点y1, y2, …,
yk,定义SG(x)为x的后继节点y1, y2, …, yk 的SG函数值构成的集合再执行mex(S)运算的结果,即: SG(x) =
mex({SG(y1), SG(y2), …, SG(yk)})
特别地,整个有向图游戏G的SG函数值被定义为有向图游戏起点s的SG函数值,即SG(G) = SG(s)。

定理:
有向图游戏的某个局面必胜,当且仅当该局面对应节点的SG函数值大于0。
有向图游戏的某个局面必败,当且仅当该局面对应节点的SG函数值等于0。

用图片举个例子

各个结点表示一种局面,红色的数字表示该局面的SG函数的值,具体的数值大小可以由Mex函数得到,当先手面临SG函数值为0的结点时必败,否则必胜,因为只要结点值不为0就一定存在下一步可以走到结点值为0的结点。(只有存在下一步结点值为0的情况当前结点才不为0)。

来道例题理解:

给定n堆石子以及一个由k个不同正整数构成的数字集合S。
现在有两位玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数量必须包含于集合S,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数k,表示数字集合S中数字的个数。
第二行包含k个整数,其中第i个整数表示数字集合S中的第i个数si。
第三行包含整数n。
第四行包含n个整数,其中第i个整数表示第i堆石子的数量hi。
输出格式
如果先手方必胜,则输出“Yes”。
否则,输出“No”。

数据范围
1≤n,k≤1001≤n,k≤100,
1≤si,hi≤10000

输入样例:
2
2 5
3
2 4 7

输出案例
Yes

大意:给定n堆石子,每次只能取任意堆石子里的指定个数,问先手必胜还是必败。

此时题目并不适应于之前的Nim问题模型,而由于每堆石子都有k种拿法,总共的拿取步骤将会是指数级别,所以这时需要将每堆石子的操作分别转化为SG函数模型,只要每堆石子的初始数量的SG函数值的异或和不为0即为必胜,否则必败。(原因同Nim游戏)

代码:(关键在于SG函数的写法)

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

int n,m,x;
int s[110],f[110];

int sg(int x)
{
    if(f[x] != -1)//记忆化搜索,保证每个结点只被搜索一次
        return f[x];
    unordered_set<int> mp;//每进入一个新的结点,set要被重置,因为结点的值只与该节点的下一步有关
    for(int i = 0; i < m; i ++ )
    {
        int sum = x - s[i];
        if(sum >= 0)//如果存在下一步的走法
            mp.insert(sg(sum));//哈希表存下一步的SG函数值
    }
    for(int i = 0; ; i ++ )
    {
        if(!mp.count(i))//Mex函数,当前结点的SG函数值为下一步结点函数值中不存在的最小自然数
            return f[x] = i;
    }
}
int main()
{
    int res = 0;
    memset(f,-1,sizeof(f));
    cin>>m;
    for(int i = 0; i < m; i ++ )
        cin>>s[i];
    cin>>n;
    while(n -- )
    {
       cin>>x;
       res ^= sg(x);
    }
    if(res)
        cout<<"Yes";
    else
        cout<<"No";
    return 0;
}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值