其他分享
首页 > 其他分享> > 【ZJSU - 大红大紫:ACM - Template】比赛用模板10:博弈论

【ZJSU - 大红大紫:ACM - Template】比赛用模板10:博弈论

作者:互联网

博弈论

巴什博奕

问题模板:

有 \(N\) 个石子,两名玩家轮流行动,按以下规则取石子:

规定:每人每次可以取走 \(X(1 \le X \le M)\) 个石子,拿到最后一颗石子的一方获胜。

双方均采用最优策略,询问谁会获胜。

两名玩家轮流报数。

规定:第一个报数的人可以报 \(X(1 \le X \le M)\) ,后报数的人需要比前者所报数大 \(Y(1 \le Y \le M)\) ,率先报到 \(N\) 的人获胜。

双方均采用最优策略,询问谁会获胜。

结论:


扩展巴什博弈

问题模板

有 \(N\) 颗石子,两名玩家轮流行动,按以下规则取石子:。

规定:每人每次可以取走 \(X(a \le X \le b)\) 个石子,如果最后剩余物品的数量小于 \(a\) 个,则不能再取,拿到最后一颗石子的一方获胜。

双方均采用最优策略,询问谁会获胜。

结论


\(\tt{}NIM\) 博弈

问题模板

有 \(N\) 堆石子,给出每一堆的石子数量,两名玩家轮流行动,按以下规则取石子:

规定:每人每次任选一堆,取走正整数颗石子,拿到最后一颗石子的一方获胜(注:几个特点是不能跨堆不能不拿)。

双方均采用最优策略,询问谁会获胜。

结论

记初始时各堆石子的数量 \((A_1,A_2, … ,A_n)\) ,定义尼姆和 \(Sum_N = A_1 \bigoplus A_2 \bigoplus … \bigoplus A_n\) 。

\(\pmb{ Sum_N = 0 }\) 时先手必败,反之先手必胜。


尼姆游戏具体取法

结论如下:

先计算出尼姆和,再对每一堆石子计算 \(A_i \bigoplus Sum_N\) ,记为 \(X_i\) 。

若得到的值 \(X_i<A_i\) ,\(X_i\) 即为一个可行解,即剩下 \(\pmb X_i\) 颗石头,取走 \(\pmb {A_i - X_i}\) 颗石头(这里取小于号是因为至少要取走 \(1\) 颗石子)。


\(\tt{} Moore’s\ Nim\) 游戏(\(\tt{}Nim - K\) 游戏)

问题模板

有 \(N\) 堆石子,给出每一堆的石子数量,两名玩家轮流行动,按以下规则取石子:

规定:每人每次任选不超过 \(K\) 堆,对每堆都取走不同的正整数颗石子,拿到最后一颗石子的一方获胜。

双方均采用最优策略,询问谁会获胜。

结论

把每一堆石子的石子数用二进制表示,定义 \(One_i\) 为二进制第 \(i\) 位上 \(1\) 的个数。

以下局面先手必胜:

对于每一位, \(\pmb{One_1,One_2,… ,One_N}\) 均不为 \(\pmb{K+1}\) 的倍数。


\(\tt{}Anti-Nim\) 游戏(反 \(\tt{}Nim\) 游戏)

问题模板

有 \(N\) 堆石子,给出每一堆的石子数量,两名玩家轮流行动,按以下规则取石子:

规定:每人每次任选一堆,取走正整数颗石子,拿到最后一颗石子的一方出局

双方均采用最优策略,询问谁会获胜。

结论


阶梯 - \(\tt{}NIM\) 博弈

模板

有 \(N\) 级台阶,每一级台阶上均有一定数量的石子,给出每一级石子的数量,两名玩家轮流行动,按以下规则操作石子:

规定:每人每次任选一级台阶,拿走正整数颗石子放到下一级台阶中,已经拿到地面上的石子不能再拿,拿到最后一颗石子的一方获胜。

双方均采用最优策略,询问谁会获胜。

结论

对奇数台阶做传统 \(\pmb{\tt{}Nim}\) 博弈,当 \(\pmb{Sum_N=0}\)** 时先手必败,反之先手必胜。**


\(\tt SG\) 游戏(有向图游戏)

我们使用以下几条规则来定义暴力求解的过程:

使用哈希表,以 \(\mathcal{O} (N + M)\) 的复杂度计算。

int n, m, a[N], num[N];
int sg(int x) {
    if (num[x] != -1) return num[x];
    
    unordered_set<int> S;
    for (int i = 1; i <= m; ++ i) 
        if(x >= a[i]) 
            S.insert(sg(x - a[i]));
    
    for (int i = 0; ; ++ i)
        if (S.count(i) == 0)
            return num[x] = i;
}
void Solve() {
    cin >> m;
    for (int i = 1; i <= m; ++ i) cin >> a[i];
    cin >> n;
    
    int ans = 0; memset(num, -1, sizeof num);
    for (int i = 1; i <= n; ++ i) {
        int x; cin >> x;
        ans ^= sg(x);
    }
    
    if (ans == 0) no;
    else yes;
}

\(\tt Anti-SG\) 游戏(反 \(\tt SG\) 游戏)

\(\tt SG\) 游戏中最先不能行动的一方获胜。

结论

以下局面先手必胜:

在本质上,这与 \(\tt Anti-Nim\) 游戏的结论一致。


\(\tt{}Lasker’s-Nim\) 游戏(\(\tt Multi-SG\) 游戏)

模板

有 \(N\) 堆石子,给出每一堆的石子数量,两名玩家轮流行动,每人每次任选以下规定的一种操作石子:

  • 任选一堆,取走正整数颗石子;
  • 任选数量大于 \(2\) 的一堆,分成两堆非空石子。

拿到最后一颗石子的一方获胜。双方均采用最优策略,询问谁会获胜。

结论

本题使用SG函数求解,SG值定义为:

\[\pmb{ SG(x) = \begin{cases} x-1 & \text{ , } x\mod 4= 0\\ x & \text{ , } x \mod 4 = 1\\ x & \text{ , } x \mod 4 = 2\\ x+1 & \text{ , } x \mod 4 = 3 \end{cases}}\]


\(\tt{}Every-SG\) 游戏

模板

给出一个有向无环图,其中 \(K\) 个顶点上放置了石子,两名玩家轮流行动,按以下规则操作石子:

移动图上所有还能够移动的石子;

无法移动石子的一方出局。双方均采用最优策略,询问谁会获胜。

结论

定义 \(step\) 为某一局游戏至多需要经过的回合数。

以下局面先手必胜:\(\pmb{step}\) 为奇数


威佐夫博弈

模板

有两堆石子,给出每一堆的石子数量,两名玩家轮流行动,每人每次任选以下规定的一种操作石子:

  • 任选一堆,取走正整数颗石子;
  • 从两队中同时取走正整数颗石子。

拿到最后一颗石子的一方获胜。双方均采用最优策略,询问谁会获胜。

结论

以下局面先手必败:

\(\pmb{ (1, 2), (3, 5), (4, 7), (6, 10), …}\) 具体而言,每一对的第一个数为此前没出现过的最小整数,第二个数为第一个数加上 \(\pmb{1,2,3,4,…}\) 。

更一般地,对于第 \(\pmb k\) 对数,第一个数为 \(\pmb {First_k= \left \lfloor \frac{k*(1+\sqrt 5)}{2} \right \rfloor}\) ,第二个数为 \(\pmb{Second_k=First_k+k}\) 。

其中,在两堆石子的数量均大于 \(10^9\) 次时,由于需要使用高精度计算,我们需要人为定义 \(\frac{1+\sqrt 5}{2}\) 的取值为 \(lorry = 1.618033988749894848204586834\) 。

const double lorry = (sqrt(5.0) + 1.0) / 2.0;
//const double lorry = 1.618033988749894848204586834;
void Solve() {
    int n, m; cin >> n >> m;
    if (n < m) swap(n, m);
    double x = n - m;
    if ((int)(lorry * x) == m) cout << "lose\n";
    else cout << "win\n";
}

斐波那契博弈

模板

有一堆石子,数量为 \(N\) ,两名玩家轮流行动,按以下规则取石子:

先手第1次可以取任意多颗,但不能全部取完,此后每人取的石子数不能超过上个人的两倍,拿到最后一颗石子的一方获胜。

双方均采用最优策略,询问谁会获胜。

结论

当且仅当 \(N\) 为斐波那契数时先手必败。

int fib[100] = {1, 2};
map<int, bool> mp;
void Force() {
  for (int i = 2; i <= 86; ++ i) fib[i] = fib[i - 1] + fib[i - 2];
    for (int i = 0; i <= 86; ++ i) mp[fib[i]] = 1;
}
void Solve() {
    int n; cin >> n;
    if (mp[n] == 1) cout << "lose\n";
    else cout << "win\n";
}

树上删边游戏

模板

给出一棵 \(N\) 个节点的有根树,两名玩家轮流行动,按以下规则操作:

选择任意一棵子树并删除(删去任意一条边,不与根相连的部分会同步被删去);

删掉最后一棵子树的一方获胜。双方均采用最优策略,询问谁会获胜。

结论

相较于传统SG值的定义,本题的SG函数值定义为:


标签:10,游戏,大红大紫,tt,石子,ZJSU,pmb,获胜,SG
来源: https://www.cnblogs.com/WIDA/p/16676294.html