Chgtaxihe's blog Chgtaxihe's blog
首页
练习
算法学习
读书笔记
小玩意

Chgtaxihe

首页
练习
算法学习
读书笔记
小玩意
  • 数论

  • 动态规划

  • 暴力

  • 图论

  • 数据结构

  • 字符串

  • 几何

  • 博弈论

    • 博弈论学习笔记
      • 策梅洛定理(Zermelo's theorem)
      • Nim(SG函数)
      • NimK
        • NimK例题 POJ 2315
      • Anti-Nim
      • 其他博弈模型
    • 威佐夫博弈
  • 其他

博弈论学习笔记

# 回合制博弈

# 策梅洛定理(Zermelo's theorem)

In game theory, Zermelo's theorem is a theorem about finite two-person games of perfect information (opens new window) in which the players move alternately and in which chance does not affect the decision making process. It says that if the game cannot end in a draw, then one of the two players must have a winning strategy (i.e. force a win). An alternate statement is that for a game meeting all of these conditions except the condition that a draw is not possible, then either the first-player can force a win, or the second-player can force a win, or both players can force a draw

如果满足以下条件

  1. 两人(A、B)博弈,交替执子(回合制)

  2. 有限回合

  3. 信息完备

  4. 不受随机性影响

那么,要么玩家A有必胜策略,要么玩家B有必胜策略,要么A、B都有必定平局的策略

如果满足

  1. 没有平局

那么,任意一方有必胜策略。

# Nim(SG函数)

假设有nnn个石子,A、BA、BA、B在游戏时轮流取走k∈S={p1,p2,…,pn}k\in S=\{p_1,p_2,\dots,p_n\}k∈S={p1​,p2​,…,pn​}个石子,无法取得石子者败(Nim)。

定义f(u)=mex{f(v)∣e(u,v)∈E}f(u)=mex\{f(v)\mid e(u,v)\in E\}f(u)=mex{f(v)∣e(u,v)∈E},其中e(u,v)e(u,v)e(u,v)代表从uuu状态可以转移到vvv状态,mex(V)mex(V)mex(V)代表不属于集合VVV的最小非负整数。

那么f(x)=0f(x)=0f(x)=0的为必败状态,f(x)≠0f(x)\ne 0f(x)=0的为必胜状态。


容易注意到,SGSGSG函数f(x)f(x)f(x)中只考虑了[0,f(x)−1][0, f(x)-1][0,f(x)−1]的状态,那么那些[f(x)+1,+∞][f(x)+1,+\infty][f(x)+1,+∞]中的可行状态呢?

假设当前状态SGSGSG值为val0val_0val0​,先手玩家将其转移为val1(val1>val0)val_1\quad(val_1>val_0)val1​(val1​>val0​)。那么根据SGSGSG函数的定义,后手玩家总可以转移到一个新状态,使得val2=val0val_2=val_0val2​=val0​,在有限步数的情况下,必胜/必败情况不变(多堆石子时也是如此)


若有多堆石子x1,x2,…,xnx_1,x_2,\dots,x_nx1​,x2​,…,xn​,可以视为多个游戏,其中每个游戏分别的SGSGSG函数f(xi)=rif(x_i)=r_if(xi​)=ri​,那么整局游戏的SGSGSG函数则为r1⊕r2⋯⊕rnr_1\oplus r_2\dots\oplus r_nr1​⊕r2​⋯⊕rn​

简要证明如下:

  1. 假设当前的状态为St=r1⊕r2⋯⊕rn=0St=r_1\oplus r_2\dots\oplus r_n=0St=r1​⊕r2​⋯⊕rn​=0,玩家必须改变某一ri(i∈[1,n])r_i(i\in[1,n])ri​(i∈[1,n]),则必然使得下一状态St′=r1′⊕r2′⋯⊕rn′≠0St'=r'_1\oplus r'_2\dots\oplus r'_n\ne 0St′=r1′​⊕r2′​⋯⊕rn′​=0(反证法可证)。

  2. 假设当前状态St≠0St\ne 0St=0,下面将证明必定存在一操作使得下一状态St′=0St'=0St′=0

    1. 记StStSt的二进制最高位位置为ppp
    2. 在rir_iri​中找到任意一个二进制第ppp位为1的值,记为rsr_srs​
    3. 将rsr_srs​第ppp位置0,低ppp位与StStSt相同,其余位不变,得到rs′<rsr'_s<r_srs′​<rs​
    4. 新的状态St′=r1⊕r2…rs−1⊕rs+1⋯⊕rn⊕rs′=0St'=r_1\oplus r_2\dots r_{s-1}\oplus r_{s+1}\dots\oplus r_n\oplus r'_s=0St′=r1​⊕r2​…rs−1​⊕rs+1​⋯⊕rn​⊕rs′​=0

这就说明了,最优策略下,St=0St=0St=0的状态必将走向St≠0St\ne0St=0的状态,St≠0St\ne0St=0的状态必将走向St=0St=0St=0的状态。

# NimK

有nnn堆石子,每堆有xix_ixi​个。玩家每次可以选择不超过kkk堆石子,并从选中的堆中取出任意数量(≥1\ge1≥1)的石子;无法取得石子者败。Nim可以看作是NimK的特例(k=1k=1k=1)。

设每堆的SGSGSG函数分别为r1,r2,…,rnr_1,r_2,\dots,r_nr1​,r2​,…,rn​,将rir_iri​的二进制表示按位相加(但不进位,每位分别对2取余)后对(k+1)(k+1)(k+1)取余得到StStSt。先手必胜的St≠0St\ne0St=0。

证明如下:

  1. 如果St=0St=0St=0,由于选择的堆数不超过kkk,根据StStSt的定义,St′≠0St'\ne0St′=0

  2. 如果St≠0St\ne0St=0,下面将证明必定存在一种操作使得下一状态St′=0St'=0St′=0

    初始时,所有rir_iri​均未被标记,记cnt0[i],cnt1[i]cnt_0[i],cnt_1[i]cnt0​[i],cnt1​[i]分别为二进制第iii位为0/10/10/1且被标记的数之个数

    1. 记StStSt的二进制最高位位置为ppp
    2. 找到任意一个二进制第ppp位为1且未被标记的值rsr_srs​
    3. 将rir_iri​的第ppp位置0,[1,p−1][1,p-1][1,p−1]位则根据该位的值,更新cnt0/cnt1cnt_0/cnt_1cnt0​/cnt1​,其余位忽略
    4. 更新后,若St′≠0St'\ne0St′=0,记Sti′≠0St'_i\ne0Sti′​=0(第iii位非零)。如果Sti′+cnt0[i]≥(k+1)St'_i+cnt_0[i]\ge(k+1)Sti′​+cnt0​[i]≥(k+1)或Sti′−cnt1[i]≤0St'_i-cnt_1[i]\le0Sti′​−cnt1​[i]≤0(当cnt0[i]+cnt1[i]=kcnt_0[i]+cnt_1[i]=kcnt0​[i]+cnt1​[i]=k时,两者至少有一个成立),则可以通过修改已经标记的rrr,使得Sti′=0St'_i=0Sti′​=0,置Sti′=0St_i'=0Sti′​=0
    5. 如果经过步骤444后St′≠0St'\ne0St′=0,则回到步骤111

    最终,St′=0St'=0St′=0且选取的堆数≤k\le k≤k

# NimK例题 POJ 2315

AC代码

#include <iostream>
#include <cstring>
#include <cmath>
#define Android ios::sync_with_stdio(false), cin.tie(NULL)

using namespace std;

const double PI = acos(-1);
int n, m, l, r;
int sg[50], bit_cnt[33];

void table(){ // 打表函数
    const int len = 50;
    int table_sg[len];
    bool appear[len];
    for(int k=1; k < 10; k++){
        cerr << "\n----------\n";
        table_sg[0] = 0;
        for(int i=1; i<len; i++){
            memset(appear, 0, sizeof appear);
            for(int j=i-1; j>=0 && i-j<=k; j--)
                appear[table_sg[j]] = true;
            for(int j=0; j<len; j++) if(!appear[j]){
                table_sg[i] = j;
                break;
            }
        }
        for(int i=1; i<len; i++) cerr << table_sg[i] << " ";
    }
}

string solve(){
    memset(bit_cnt, 0, sizeof bit_cnt);
    double cir = 2 * PI * r; // 
    int max_k = l / cir;
    for(int i=1; i<=n; i++) {
        cin >> sg[i];
        sg[i] = ((int)ceil(sg[i] / cir)) % (max_k + 1); // 打表得出SG函数规律
        // 由于Pi是无理数(不能写作两整数之比),因此可以把ceil换成+1
    }
    for(int i=1; i<=n; i++){
        for(int j=0; j<31; j++){
            if(sg[i] & (1<<j)) bit_cnt[j]++;
        }
    }
    for(int j=0; j<31; j++){
        if(bit_cnt[j] % (m + 1) != 0) return "Alice";
    }
    return "Bob";
}

signed main(){
    Android;
    while(cin >> n >> m >> l >> r) cout << solve() << '\n';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# Anti-Nim

有nnn堆石子,每堆分别有x1,x2,…,xnx_1,x_2,\dots,x_nx1​,x2​,…,xn​个,每次只能从一堆中取出任意数目的石子,取走最后一个石子者败。

显然对于单个堆,SG(i)=xiSG(i)=x_iSG(i)=xi​,对于整局游戏,SG=x1⊕x2⋯⊕xnSG=x1\oplus x_2\dots\oplus x_nSG=x1⊕x2​⋯⊕xn​

先手必胜当且仅当:

  1. 所有xix_ixi​都为111,且整局的SG=0SG=0SG=0
  2. 存在xi≠1x_i\ne1xi​=1,且整局的SG≠0SG\ne0SG=0

注意:我们规定,SG=0SG=0SG=0的局面不一定为必败局面

证明见 贾志豪《组合游戏略述——浅谈SG游戏的若干拓展及变形》

# 其他博弈模型

除了上述模型以外,还有许多博弈模型,如

  • Every-SG
  • 威佐夫博弈(Wythoff's game)
  • Fibonacci Nim
  • Staircase Nim
  • 非回合制博弈

等等

# 参考

wiki-Zermelo's theorem (game theory) (opens new window)

10170 Sprague-Grundy定理是怎么想出来的 (opens new window)

上次更新: 2021/02/24, 03:37:30
皮克定理
威佐夫博弈

← 皮克定理 威佐夫博弈→

最近更新
01
深入理解Java虚拟机
03-04
02
DNS工作原理
02-27
03
改用VuePress啦
02-23
更多文章>
Theme by Vdoing | Copyright © 2019-2021
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式