小工具知识网

当前位置: 首页 > 行业知识 > 博弈论,NIM游戏,台阶型,集合型,SG函数,详解

行业知识

博弈论,NIM游戏,台阶型,集合型,SG函数,详解

2026-11-03 19:10:09 来源:互联网转载

文章目录

    • 一、Nim游戏
      • 1.1问题描述
      • 1.2定理
        • 1.2.1定理内容
        • 1.2.2定理证明
        • 1.3OJ练习
          • 1.3.1模板OJ
          • 1.3.2P1247 取火柴游戏
          • 二、台阶型Nim游戏
            • 2.1问题描述
            • 2.2结论及证明
              • 2.2.1结论
              • 2.2.2结论证明
              • 2.3OJ练习
                • 2.3.1Georgia and Bob
                • 三、有向图游戏,SG函数
                  • 3.1定义
                    • 3.1.1有向图游戏
                    • 3.1.2Mex运算
                    • 3.1.3SG函数
                    • 3.1.4有向图游戏的和
                    • 3.2定理及证明
                      • 3.2.1定理内容
                      • 3.2.1定理证明
                      • 3.3有向无环图上的棋子游戏
                        • 3.3.1问题描述
                        • 3.3.2思路分析
                        • 3.3.3原题链接
                        • 3.3.4AC代码
                        • 3.4 集合型NIM游戏
                          • 3.4.1问题描述
                          • 3.4.2思路分析
                          • 3.4.3原题链接
                          • 3.4.4AC代码
                          • 3.5普通NIM游戏与有向图游戏的关系
                          • 3.6OJ练习-POJCutting Game
                            • 3.6.1原题链接
                            • 3.6.2思路分析
                            • 3.6.3AC代码

                              一、Nim游戏

                              1.1问题描述

                              甲,乙两个人玩 nim 取石子游戏。

                              nim 游戏的规则是这样的:地上有 n 堆石子(每堆石子数量小于 10^4),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这 n 堆石子的数量,他想知道是否存在先手必胜的策略。

                              上面这种游戏被称为NIM博弈。对于游戏过程中面临的状态,如果玩家在这种状态下无论进行任何行动,都会输掉游戏,我们称该状态为必败态。同样的,如果玩家在这种状态下无论进行任何行动,都会赢得游戏,我们称该状态为必胜态。

                              1.2定理

                              1.2.1定理内容

                              NIM博弈先手必胜,当且仅当 A1 ^ A2 ^ …… ^ An ≠ 0

                              1.2.2定理证明

                              下面采用的证明方法是NIM博弈问题常用证明方法:

                              • 证明:必胜态的后继状态至少存在一个必败态
                                • 若A1 ^ A2 ^ …… ^ An = s,设s最高位是第k位,则A1~An中有奇数个第k位为1,不妨从中取出Ai,那么Ai ^ s > n, res = 0; for (int i = 0, a; i > a, res ^= a; res ? cout _; while (_--) solve(); return 0;}
                                  1.3.2P1247 取火柴游戏

                                  原题链接

                                  P1247 取火柴游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

                                  AC代码

                                  #include #include using namespace std;#define int long longconst int N = 5e5 + 10, mod = 1e9 + 7;int n, res, a[N];void solve(){    cin >> n, res = 0;    for (int i = 0; i > a[i], res ^= a[i];    if (!res)    {        cout = a[i])            continue;        cout > 1;    if (c > n;    for (int i = 0; i > datas[i].i >> datas[i].x >> datas[i].y;        if (datas[i].i == 1)            id[++tot] = datas[i].x;    }    sort(id + 1, id + tot + 1);    tot = unique(id + 1, id + tot + 1) - id - 1;    build(1, 1, tot);    for (int i = 0, a, b; i  m >> k;    for (int i = 0, a, b; i > a >> b, addedge(a, b);    for (int i = 0, x; i > x, res ^= sg(x);    res ? cout  _;    while (_--)        solve();    return 0;}

                                  3.4 集合型NIM游戏

                                  3.4.1问题描述

                                  给定m个整数组成的集合ai,给定n堆石子的数量bi。

                                  两名玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数目必须是集合a中的整数,最后无法进行操作的人视为失败。

                                  如果两人都采用最优策略,问先手是否必胜。

                                  3.4.2思路分析

                                  每堆石子都是孤立的,把n堆石子看做n个有向图游戏。然后利用SG定理即可。

                                  对于子节点的寻找直接根据集合a内元素进行判断即可,省去了建图。

                                  3.4.3原题链接

                                  Problem - 1536 (hdu.edu.cn)

                                  3.4.4AC代码
                                  #include #include #include using namespace std;#define int long longconst int N = 10005, M = 105, mod = 1e9 + 7;int a[M], f[N], k, m, n;int sg(int x){    if (~f[x])        return f[x];    bool vis[M]{0};    for (int i = 0; i = a[i]; i++)        vis[sg(x - a[i])] = 1;    for (int i = 0;; i++)        if (!vis[i])            return f[x] = i;    return -1;}void solve(){    while (cin >> k, k)    {        memset(f, -1, sizeof f);        for (int i = 0; i > a[i];        sort(a, a + k), cin >> m;        while (m--)        {            cin >> n;            int res = 0;            for (int i = 0, x; i > x, res ^= sg(x);            res ? cout 

上一篇:ios服务器怎么填?

下一篇:印度服务器怎么建的?