首页 > 其他分享 >博弈论总结

博弈论总结

时间:2023-08-14 22:33:04浏览次数:47  
标签:总结 石子 xor 游戏 博弈论 必胜 SG 节点

博弈论题目解题的关键在于找到一个状态a,设它的否定为状态b,状态a满足:不论怎么操作对手的状态a一定会转化为状态b和一定存在一种从状态b转化到状态a的操作。满足这样两条性质的状态a为必败态,b为必胜态。 想求SG,需要对后续节点实行mex函数,想求是否为必胜必败态,需要求异或和 如果使用SG来做,不需要分析什么,直接对所有子游戏求异或和最后判断与0的关系即可(对应Nim游戏的推广);如果不使用SG,那么就需要分析出必败态和必胜态,(对应Nim游戏)

Nim游戏

给定n堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。问如果两人都采用最优策略,先手是否必胜。

Nim定理

假设各堆石子数量为$A_1, A_2, ..., A_n$,那么先手必胜的充分必要条件为 $A_1 \ xor \ A_2 \ xor \ ... \ xor \ A_n \ \neq \ 0$

定理证明

前提说明 为何本题使用异或进行判断不是我们能想到的,那是数学家的工作,我们能做的就是理解相关定理的证明并记忆相关题目的特征。 首先必须明确一个必败局面是**$A_1 \ xor \ A_2 \ xor \ ... \ xor \ A_n \ = \ 0$,该结论在《算法竞赛进阶指南》中并没有给出详细说明,书中的说法是当所有石子数量均为0时是先手必败局面,此时$A_1 \ xor \ A_2 \ xor \ ... \ xor \ A_n \ = \ 0$,但是这只是一种特殊情况,并非一般情况,所以这里我也不太清楚,不过由于后续证明必须用到这个结论,所以这里只能先暂时这么认定。 证明 若想要证明异或和不为0是先手必胜的条件,也就是证明异或和不为0的状态x是一个必胜态,需要从以下两个角度进行证明 一、通过某些操作可以使得状态x到达必败态,当先手处于必胜局面时,必须保证对手面对的一定是必败局面,即通过某个**操作可以使得任意一个必胜局面转化为必败局面

对于任意一个局面,如果$A_1 \ xor \ A_2 \ xor \ ... \ xor \ A_n \ = \ x \ \neq \ 0$,设x的二进制表示下最高位的1在第$k$位,那么至少存在一个$A_i$,它的$k$位是1,因为$x \ xor \ x = 0$,所以我们只需要从$A_i$中拿走$A_i - (A_i \ xor \ x)$,使得$A_i$变为$A_i xor x$,从而得到$A_1 \ xor \ A_2 \ xor \ (A_i \ xor \ x) \ ... \ xor \ A_n \ = A_1 \ xor \ A_2 \ xor \ ... \ xor \ A_n \ = \ x \ xor \ x \ = \ 0$的必败局面

二、不论采取什么操作必败态一定会转化为状态x,,当对手处于必败局面时,必须保证先手面对的一定是必胜局面,即通过任何操作可以使得任意一个必败局面转化为必胜局面

对于任意一个局面,如果$A_1 \ xor \ A_2 \ xor \ A_i \ ... \ xor \ A_n \ = \ 0$(1式),那么无论如何取石子,都可以得到所有石子数量异或和不为0的局面,即必胜局面。采用反证法,假设从$A_i$中取出一些石子后数量变为$A_i^{'}$,且$A_1 \ xor \ A_2 \ xor \ A_i^{'} \ ... \ xor \ A_n \ = \ 0$(2式),将1式和2式左右两侧分别进行异或,结果为$A_i \ xor \ A_i^{'} \ = \ 0$,即$A_i \ = \ A_i^{'}$,这显然和假设是矛盾的,所以对于一个必败局面,无论从哪堆石子中取出多少石子都一定得到一个必胜局面

注意上方两点中“某个”和“任意”的区别,某个是指并非所有操作都可以达到上方所说的效果,但是一定有一个可以,而且题目要求可以保证每次都选择最优方案,所以一定可以选择到那个特定的操作;任意是指无论如何操作都一定会有那个效果,即使按照每次选择最优方案的策略都会有这样的效果

代码实现

只需要按照Nim定理进行判断即可

Nim游戏的推广

名词和定理

公平组合游戏 上述的Nim游戏实际为一个公平组合游戏(ICG: Impartial Combinatorial Games),其满足几点特征~~(其实也就是了解一下,做题没啥用)~~

  • 由两名玩家交替进行
  • 在游戏进程的任意时刻,可以执行的合法行动与轮到哪名玩家无关
  • 不能行动的玩家判负(输)

有向图游戏 给定一个有向无环图,图中有唯一一个起点,在起点上放有一枚棋子。两名玩家交替将棋子沿着有向边移动,每次可以移动一次,无法移动者判定为输(判负)。 如果将游戏过程中每一个局面(状态)看为图中的一个节点,局面的变化看为节点沿着有向边的移动,任意一个公平组合游戏都可以看为是一个有向图游戏。

mex运算 设S为一个非负整数集合,mex(S)含义为求出不属于集合S的最小非负整数,即: $mex(S) = \displaystyle \min_{x \ \in \ N, \ x \ \notin \ S}{x}$

SG函数 在有向图游戏中,对于每个节点x,设从x出发共有k条有向边,分别到达$y_1, y_2, ..., y_k$,定义SG(x)为x的后继节点$y_1, y_2, ..., y_k$的SG函数值构成的集合执行mex的结果,即: $SG(x) \ = \ mex({SG(y_1), SG(y_2), \ ... \ ,SG(y_k)})$ 实际效果见下图: 有向图游戏G的SG函数值定义为游戏起点的SG函数值。

有向图游戏的和 有向图游戏的和的SG函数值等于各个子游戏SG函数值的异或和(游戏的SG函数值概念见SG函数最后一行)

定理

有向图游戏的某个局面必胜,当且仅当该局面对应节点的SG函数值>0 有向图游戏某个局面必败,当且仅当该局面对应节点的SG函数值=0

原因在于SG函数值为0代表到达了不能行动的局面,自然对应着必败局面;SG函数值非0表示后续节点中包含终点,即可以使得对手到达不能行动的局面,则对应必胜局面

注意定理提到的只是一个子问题,比如只有一堆石子,每次可以拿固定数量的石子,询问先手是否必胜。根据最初节点的SG函数值即可判断初始节点是否为必胜态。但是实际问题一定都是多个子问题,比如有多堆石子,每次可以拿固定数量的石子,询问先手是否必胜。对于多个子问题,是否先手必胜取决于各个子问题SG函数值的异或和,即取决于有向图游戏的和,书中并没有证明该结论,只是提到与上述Nim游戏的证明类似,但是我暂时并没有想懂。

举例

给定n堆石子以及一个由k个不同正整数构成的数字集合S。 现在有两位玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数量必须包含于集合S,最后无法进行操作的人视为失败。 问如果两人都采用最优策略,先手是否必胜。

分析 其实上面提到的Nim游戏可以看为是该题的特例,特殊在k=1,s中只有一个数据1。 可以看出本题就是定理中提到的多个子问题的情况,解题关键在于求解出每一个子游戏的SG函数值,我们考虑时只需要考虑一个子游戏,然后遍历求解即可。对于某一个节点的SG,取决于其后续节点的SG,所以代码实现是递归。同时考虑到不同子游戏中相同状态的节点(状态在本题中指堆中石子数量)的SG其实是相等的,因为对于该节点而言,无论处于哪个子游戏中,它延伸出的后续节点都是一样的,根据SG函数的本质求解方式,不同子游戏相同状态的节点SG显然是相等的,所以递归采用记忆化来降低复杂度。 对于记忆化的进一步解释可以查看下图,红色框的两部分目的都是计算石子数量为3对应节点的SG函数值,显然计算4会递归计算3,如果此前计算过3那么此时就没有必要再算一次了,能够记忆化的关键在于不同子游戏中相同状态节点的SG是相等的。

代码实现

/**
 * 在计算某节点的SG时需要先求解所有后续节点的SG,之后选择一个最小且不在这些SG值中的非负整数值
 * 实现方式很多,可以用数组存储然后从小到大排序并从小到大依次查看,第一个没有出现的数值就符合我们的要求,这样做时间复杂度的瓶颈在于排序,最快也要O(nlogn)
 * 但是我们在计算节点x的SG时,只需要判断某个值是否属于所有后续节点的SG值集合中,采用哈希是更好的方案
 * 如果使用STL,使用unordered_map和unordered_set均可,代码中注释部分为使用unordered_map的实现方式
 */
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <cstring>

using namespace std;

const int N = 110, M = 10010;

int m, s[N];
int n, f[M]; // f[i]:石子数量为i对应的节点的SG函数值

int sg(int x)
{
    if (f[x] != -1) return f[x];
    
    unordered_set<int> S;
    // unordered_map<int, bool> S;
    for (int i = 0; i < m; ++ i)
        if (x >= s[i])
            S.insert(sg(x - s[i])); // 把x的所有后续节点的sg先存储下来
            // S[sg(x - s[i])] = true;
    
    // 找到不在集合中且最小的值作为x节点的SG值
    for (int i = 0; ; ++ i)
        if (!S.count(i)) // count:统计set中i的数量,由于set会去重,所以返回值为0或者1
        // if (!S[i]) 
            return f[x] = i;
}
int main()
{
    cin >> m;
    for (int i = 0; i < m; ++ i) cin >> s[i];
    cin >> n;
    
    memset(f, -1, sizeof f);
    int res = 0;
    while (n --)
    {
        int x;
        cin >> x;
        res ^= sg(x);
    }
    
    if (res) cout << "Yes" << endl;
    else cout << "No" << endl;
    
    return 0;
}

标签:总结,石子,xor,游戏,博弈论,必胜,SG,节点
From: https://blog.51cto.com/u_14882565/7082292

相关文章

  • NFLS 训练总结 2(updating)
    前言接上周。Day6总体情况1000+1200+1400+1700+1800+1408+0+300=8808,rk83大寄,为什么他们分都那么高啊!T1从T1就开始卡。简单的贪心,买票最少就是每个大人都尽量带孩子,而最多就是所有孩子都由一个大人带。如果没有大人只有孩子,就是“Impossible”。然后有人Impossibl......
  • 20230814巴蜀暑期集训测试总结
    T2考场一直卡在二进制思路里面,最后打了一个\(O(n\max\{a_i\})\)的方法,居然忘了继续向后跑\(\log\)位,挂掉\(20pts\)(像这种情况全挂也是有可能的)。我认为其实有的时候不要随便简化问题,或者说想多了也要及时回来(虽然这可能很不容易)。自己认为的简化不一定就把题目变简单了。像......
  • 博弈论
    博弈论%%happyguy笔记nim游戏堆异或和取最大的一堆后异或和为零,变为先手必败。枚举所有可能情况作为有向无环图,直到全为0,必败。全败,必败。有胜,必胜。此例子,123为一个环,平局,尽头为先手必败(已经败了),可以向上递推。arc143c两个人都在一堆取,此堆至少(x+y)个。必胜的一方......
  • 8.14总结
    真的让人去世,我对于熬通宵本来不太适合,还得爬山这种体力活,到了中天门已经困到不行了,当时都打算放弃了,然后我就眯了一会,大约调整了半个小时,之后体力恢复多了,就想着来都来了,然后默默开始一点一点往上爬,最后爬上去了,感觉跟梦一样,然后腿脚就废了,真的不想来第二次了,不过真的很惊叹这次......
  • 8.13总结
    今天早早收拾好行李,去爬泰山了,听说泰山会制服每一个嘴硬的人,跟着其他三个朋友前去。到了地方,找好民宿后我i们坐在一起聊聊天没很享受这种氛围,晚上一起去外面吃了个饭,吃饱后我们步行回民宿去,准备去泰山了,大约十点半多年开始爬,希望能成功登顶......
  • webkit webApp 开发技术要点总结
    如果你是一名前端er,又想在移动设备上开发出自己的应用,那怎么实现呢?幸好,webkit内核的浏览器能帮助我们完成这一切。接触webkitwebApp的开发已经有一段时间了,现把一些技巧分享给大家:1.viewport:也就是可视区域。对于桌面浏览器,我们都很清楚viewport是什么,就是出去了所有工具栏、......
  • Hibernate 实体关联关系映射----总结
    http://lavasoft.blog.51cto.com/62575/39398Hibernate实体关联关系映射----总结 花了三天的业余时间,终于写完了Hibernate关联关系映射的所有实例,感觉还应该总结一下。 Hibernate映射关系错综复杂,在实际中真的都能用到吗?不用行吗? 在我......
  • 周总结6
    ·数据库本身是个独立运行的应用程序·撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找·JDBC(JavaDataBaseConnectivity)是Java联机数据库的标准规范·定义一组标准类与接口,应用程序需要联机数据库时调用这组标准API,标准API中接口会由数据库厂商操作,称为JDB......
  • 编程题算法总结
    求最大公约数最小公倍数最大公约数辗转相除法大的a除小的b,得到余数如果是0,那么b就是最大公约数,否则就取余数做那个小的,本来的b就成了大的继续操作。intn,m;//辗转相除法,ab最大公约数=ab余数和b的最大公约数intyu,a,b;a=n>m?n:m;b=n>m?m:n......
  • 【Alibaba中间件技术系列】「RocketMQ技术专题」帮你梳理RocketMQ相关的消费问题以及
    推荐超值课程:点击获取消息重复消费的问题消息重复消费是各个MQ都会发生的常见问题之一,在一些比较敏感的场景下,重复消费会造成比较严重的后果,比如重复扣款等。消息重复消费场景及解决办法在什么情况下会发生RocketMQ的消息重复消费呢?生产者重复发送场景当系统的调用链路比......