首页 > 编程语言 >算法学习笔记(42)——博弈论

算法学习笔记(42)——博弈论

时间:2022-12-10 09:46:03浏览次数:56  
标签:局面 有向图 游戏 int 博弈论 42 算法 oplus SG

博弈论

NIM 博弈

给定 \(n\) 堆物品,第 \(i\) 堆物品有 \(A_i\) 个。两位玩家轮流操作,每次操作可以任选一堆,拿走任意数量的物品(可以拿完,但不能不拿),最后无法进行操作的人视为失败,取走最后一件物品者获胜。
问如果两人都采用最优策略,先手是否必胜。

我们把这种游戏称为 NIM 博弈。把游戏过程中面临的状态称为局面。整局游戏第一个行动的称为先手,第二个行动的称为后手。若在某一局面下无论采取何种行动,都会输掉游戏,则称该局面必败。所谓采取最优策略是指,若在某一局面下存在某种行动,使得行动后对手面临必败局面,则优先采取该行动。同时,这样的局面被称为必胜。我们讨论的博弈问题一般都只考虑理想情况,即两人均无失误,都采取最优策略行动时游戏的结果。NIM 博弈不存在平局,只有先手必胜先手必败两种情况。

定理
NIM博弈先手必胜,当且仅当 \(A_1 \oplus A_2 \oplus \cdots \oplus A_n \neq 0\) 。

证明
所有物品都被取光是一个必收局面(对手取走最后一件物品,已经获得胜利),此时显然有 \(A1 \oplus A_2 \oplus \cdots \oplus A_n = 0\) 。

对于任意一个局面,如果 \(A1 \oplus A_2 \oplus \cdots \oplus A_n = x \neq 0\) ,设 \(x\) 的二进制表示下最高位的 \(1\) 在第 \(k\) 位,那么至少存在一堆石子 \(A_i\) ,它的第 \(k\) 位是 \(1\) 。显然 \(Ai \oplus x < A_i\) ( \(x\) 与 \(A_i\) 的最高位都是 \(1\) ,异或变为 \(0\) ),我们就从 \(A_i\) 堆中取走若干石子,使其变为 \(A_i \oplus x\) , 就得到了一个各堆石子数异或起来等于 \(0\) 的局面。

对于任意一个局面,如果 \(A_1 \oplus A_2 \oplus \cdots \oplus A_n = 0\) ,那么无论如何取石子,得到的局面下各堆石子异或起来都不等于 \(0\) 。可用反证法证明,假设 \(A_i\) 被取成了 \(A_i'\),并且 \(A_1 \oplus A_2 \oplus \cdots \oplus A_i' \oplus \cdots \oplus A_n=0\) 。由异或运算的消去律得 \(A_i' = A_i\), 与 "不能不取石子" 的规则矛盾。

综上所述,再由数学归纳法可知,\(A_1 \oplus A_2 \oplus \cdots \oplus A_n \neq 0\) 为必胜局面,一定存在一种行动让对手面临 "各堆石子异或起来等于 \(0\) "。\(A_1 \oplus A_2 \oplus \cdots \oplus A_n = 0\) 为必败局面,无论如何行动,都会让对手面临一个 "各堆石子异或起来不等于 \(0\) " 的必胜局面。

证毕。

题目链接:AcWing 891. Nim游戏

#include <iostream>

using namespace std;

int main()
{
    int n;
    scanf("%d", &n);
    int res = 0;
    while (n -- ) {
        int x;
        scanf("%d", &x);
        res ^= x;
    }
    
    if (res) puts("Yes");
    else puts("No");
    
    return 0;
}

台阶-Nim游戏

定理
台阶NIM博弈先手必胜,当且仅当奇数项 \(A_1 \oplus A_3 \oplus \cdots \oplus A_{2n-1} \neq 0\) 。

证明
先手时,如果奇数台阶异或非0,根据经典Nim游戏,先手总有一种方式使奇数台阶异或为0,于是先手留了奇数台阶异或为0的状态给后手
于是轮到后手:

  1. 当后手移动偶数台阶上的石子时,先手只需将对手移动的石子继续移到下一个台阶,这样奇数台阶的石子相当于没变,于是留给后手的又是奇数台阶异或为0的状态
  2. 当后手移动奇数台阶上的石子时,留给先手的奇数台阶异或非0,根据经典Nim游戏,先手总能找出一种方案使奇数台阶异或为0
    因此无论后手如何移动,先手总能通过操作把奇数异或为0的情况留给后手,当奇数台阶全为0时,只留下偶数台阶上有石子。
    (核心就是:先手总是把奇数台阶异或为0的状态留给对面,即总是将必败态交给对面)

因为偶数台阶上的石子要想移动到地面,必然需要经过偶数次移动,又因为奇数台阶全0的情况是留给后手的,因此先手总是可以将石子移动到地面,当将最后一个(堆)石子移动到地面时,后手无法操作,即后手失败。

因此如果先手时奇数台阶上的值的异或值为非0,则先手必胜,反之必败!

题目链接:AcWing 892. 台阶-Nim游戏

#include <iostream>

using namespace std;

int main()
{
    int n;
    int res = 0;
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ ) {
        int a;
        scanf("%d", &a);
        if (i % 2) res ^= a;
    }
    
    if (res) puts("Yes");
    else puts("No");
    
    return 0;
}

公平组合游戏ICG

若一个游戏满足:

  1. 由两名玩家交替行动:
  2. 在游戏进程的任意时刻,可以执行的合法行动与轮到哪名玩家无关:
  3. 不能行动的玩家判负。

则称该游戏为一个公平组合游戏。

NIM博弈属于公平组合游戏,但常见的棋类游戏,比如国棋,就不是公平组合游戏。因为围棋交战双方分别只能落黑子和白子,胜负判定也比较复杂,不满足条件2和
条件3。

有向图游戏

给定一个有向无环图,图中有一个唯一的起点,在起点上放有一枚棋子。两名玩家交替地把这枚棋子沿有向边进行移动,每次可以移动一步,无法移动者判负。该游戏被称为有向图游戏
任何一个公平组合游戏都可以转化为有向图游戏。具体方法是,把每个局面看成图中的一个节点,并且从每个局面向沿着合法行动能够到达的下一个局面连有向边。

Mex 运算

设 \(S\) 表示一个非负整数集合。定义 \(mex(S)\) 为求出不属于集合 \(S\) 的最小非负整数的运算,即:

\[mex(s) = \min_{x \in \mathbb{N}, x \notin S} \lbrace x \rbrace \]

SG 函数

在有向图游戏中,对于每个节点 \(x\) ,设从 \(x\) 出发共有 \(k\) 条有向边,分别到达节点 \(y_1,y_2, \cdots ,y_k\) ,定义 \(SG(x)\) 为 \(x\) 的后继节点 \(y_1,y_2, \cdots ,y_k\) 的 \(SG\) 函数值构成的集合再执行 \(mex\) 运算的结果,即:

\[SG(x) = mex (\lbrace SG(y_1), SG(y_2), \cdots , SG(y_k) \rbrace) \]

特别地,整个有向图游戏 \(G\) 的 \(SG\) 函数值被定义为有向图游戏起点 \(s\) 的 \(SG\) 函数值,即 \(SG(G) = SG(s)\) 。

有向图游戏的和

设 \(G_1,G_2,\cdots,G_m\) 是 \(m\) 个有向图游戏。定义有向图游戏 \(G\) ,它的行动规则是任选某个有向图游戏 \(G_i\) ,并在 \(G_i\) 上行动一步。\(G\) 被称为有向图游戏 \(C_1,G_2,\cdots,G_m\) 的和。
有向图游戏的和的 \(SG\) 两数值等于它包含的各个子游戏 \(SG\) 函数值的异或和,即:

\[SG(G) = SG(G_1) \oplus SG(G_2) \oplus \dots \oplus SG(G_m) \]

定理

  • 有向图游戏的某个局面必胜,当且仅当该局面对应节点的 \(SG\) 函数值大于 \(0\)。
  • 有向图游戏的某个局面必败,当且仅当该局面对应节点的 \(SG\) 两数值等于 \(0\)。

我们不再详细证明该定理。可以这样理解:

  • 在一个没有出边的节点上,棋子不能移动,它的 \(SG\) 值为 \(0\),对应必败局面。
  • 若一个节点的某个后继节点 \(SG\) 值为 \(0\),在 \(mex\) 运算后,该节点的 \(SG\) 值大于 \(0\) 。这等价于,若一个局面的后继局面中存在必败局面,则当前局面为必胜局面
  • 若一个节点的后继节点 \(SG\) 值均不为 \(0\),在 \(mex\) 运算后,该节点的 \(SG\) 值为 \(0\)。这等价于,若一个局面的后继局面全部为必胜局面,则当前局面为必败局面
  • 对于若千个有向图游戏的和,其证明方法与 NIM 博弈类似。

集合-Nim游戏

题目链接:AcWing 893. 集合-Nim游戏

#include <iostream>
#include <cstring>
#include <unordered_set>

using namespace std;

const int N = 110, M = 10010;

int n, k;
int s[N];   // 石子个数
int f[M];   // SG函数的值

int sg(int x)
{
    // 记忆化搜索,如果某个状态被算过,不重复计算,直接返回
    // 保证时间复杂不是指数级别,每个状态只会被计算一次
    if (f[x] != -1) return f[x];
    
    // 用哈希表存储当前局面可以到的局面
    unordered_set<int> S;
    
    // 枚举每个可操作的数
    for (int i = 0; i < k; i ++ ) {
        int sum = s[i];
        // 如果能够操作,就将下一局面加入哈希表
        if (x >= sum) S.insert(sg(x - sum));
    }
    
    // mex操作:求出不属于集合 S 的最小非负整数
    for (int i = 0; ; i ++ )
        if (!S.count(i))
            return f[x] = i;
}

int main()
{
    cin >> k;
    for (int i = 0; i < k; i ++ ) cin >> s[i];
    cin >> n;
    
    memset(f, -1, sizeof f);
    
    int res = 0;
    // 分别求每一堆的石子SG函数值,并计算各个子游戏函数值的异或和
    for (int i = 0; i < n; i ++ ) {
        int x;
        cin >> x;
        res ^= sg(x);
    }
    
    if (res) puts("Yes");
    else puts("No");
    
    return 0;
}

拆分-Nim游戏

题目链接:AcWing 894. 拆分-Nim游戏

相比于集合-Nim游戏,这里的每一堆可以变成小于原来那堆的任意大小的两堆
a[i]可以拆分成(b[i],b[j]),为了避免重复,规定b[i]>=b[j],即:a[i]>b[i]>=b[j]

相当于一个局面拆分成了两个局面,由SG函数理论,多个独立局面的SG
值,等于这些局面SG值的异或和。因此需要存储的状态就是sg(b[i]) ^sg(b[j])(与集合-Nim的唯一区别)

PS:因为这题中原堆拆分成的两个较小堆小于原堆即可,因此任意一个较小堆的拆分情况会被完全包含在较大堆中,因此S可以开全局。

#include <iostream>
#include <cstring>
#include <unordered_set>

using namespace std;

const int N = 110;

int n;
int f[N]; // 存储SG函数值

int sg(int x)
{
    if (f[x] != -1) return f[x];
    
    unordered_set<int> hash;
    for (int i = 0; i < x; i ++ )
        for (int j = 0; j <= i; j ++ )
            hash.insert(sg(i) ^ sg(j));
    
    // mex操作
    for (int i = 0; ; i ++ )
        if (!hash.count(i))
            return f[x] = i;
}

int main()
{
    scanf("%d", &n);
    
    memset(f, -1, sizeof f);    // 记忆化搜索
    
    int res = 0;
    while (n -- ) {
        int a;
        scanf("%d", &a);
        res ^= sg(a);
    }
    
    if (res) puts("Yes");
    else puts("No");
    
    return 0;
}

标签:局面,有向图,游戏,int,博弈论,42,算法,oplus,SG
From: https://www.cnblogs.com/I-am-Sino/p/16970799.html

相关文章