博弈论相关问题
SG函数
适用范围
- 两人、轮流操作
- 信息公开透明
- 没有随机因素
- 有限步内必然结束
- 不存在平局
- 决策集合为空的游戏者输(即不能操作者输)
- 可以将每个局面中的元素单独分析,元素之间不会有依赖关系(即一次可以选两个元素等)
策梅洛定理:对于这样的一个游戏,任何一个局面先手或者后手其中之一必然存在必胜策略
性质
- 对于当前的局面,定义其函数值为。其中,先手必胜当且仅当,反之后手必胜
- 若,则。特别地,这里的指的是局面上的组合(可理解为并集)而非数量加和。即,
- (表示可以通过一步操作变换到)。从而一次博弈过程可以看成一棵有向无环树。那么结束节点为(根据定义)
应用(ABC206F)
注意到覆盖值域只有,则初始局面(表示在当前局面中,第个位置还没有被覆盖过。)
注意到覆盖或没覆盖过的地方一定是一段连续的位置。则我们用来表示,即
用记忆化搜索来求解。设当前局面为,若,
否则考虑如何得来。在个区间中,我们可以选择一个区间满足并将其覆盖。此时,,那么,可以递归求解。得到后,就可以通过求出了。
code
int dfs(int l, int r)
{
if (l > r) return 0;
if (sg[l][r] != -1) return sg[l][r];
int bk[105]; memset(bk, 0, sizeof(bk));
for (int i = l; i <= r; i ++ )
{
for (int o = 0; o < (int)p[i].size(); o ++ )
{
int j = p[i][o];
if (j > r) continue;
bk[dfs(l, i - 1) ^ dfs(j + 1, r)] = 1;
}
}
for (int i = 0; ; i ++ ) if (!bk[i]) return sg[l][r] = i;
}
int main()
{
t = read();
while (t -- )
{
for (int i = 1; i <= 99; i ++ ) p[i].clear();
n = read();
for (int i = 1; i <= n; i ++ )
{
int x = read(), y = read();
p[x].pb(y - 1);
}
memset(sg, -1, sizeof(sg));
if (dfs(1, 99)) puts("Alice");
else puts("Bob");
}
return 0;
}
Anti-SG函数
适用范围
- 决策集合为空的游戏者赢(即不能操作者赢,也可以理解为操作最后一步者输)
- 其他同SG函数
性质:SJ定理
设初始状态为,则先手必胜当且仅当下列两种情况的任意一种成立:(下面函数的定义没有改变)
Nim博弈
Description
两个人玩取石子游戏:地上有堆石子(每堆石子数量小于),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。求是否存在先手必胜的策略。
Solution
设这堆石子分别为。则先手必胜当且仅当,反之后手必胜
简要证明:,
又(每次可以取个石头),
故时先手必胜,反之后手必胜
阶梯Nim问题
Description
有个位置,每个位置上有个石子。两个人轮流操作,步骤是:挑选中任意一个存在石子的位置,将至少个石子移动至位置(则最后所有石子都堆在在这个位置),谁不能操作谁输。求先手必胜还是必败。
Solution
结论:该问题相当于所有奇数位置的石子做Nim博弈。
证明:假设两个人都只会移动奇数位置的石子(并移到偶数位置上去),这相当于所有奇数位置的石子做Nim博弈(移到偶数位置,等价于在奇数位置取石子,因为偶数位置的石子无论怎样都不会造成影响)
这样可以求出是先手必胜/后手必胜。不妨令先手必胜,则先手一定能通过只移动奇数位置上的石子获胜。因为若后手也只移动奇数位置上的石子,先手必胜;若后手某一步移动了偶数位置的石子,先手可以紧接着把被移动的石子再移动到下一个偶数位置。这样,所有奇数位置的石子数量没有变,只有偶数位置的改变了,但这是没有影响的,故新问题与原问题等价。
应用(P2575)
注意到一次只能对一行操作,而整个棋盘相当于这行的组合。所以对每一行算出值并异或,即可判断。
因为某一行的石子之间是会相互影响的,不好直接算函数,考虑模型转化。
阶梯Nim问题要考虑不变量来划分阶段。注意到空格的数目是不变的。于是我们想到把每个空格右边有多少个连续的石子,作为该位置的石子数。这样就转化成了阶梯Nim问题。
code
#include <bits/stdc++.h>
using namespace std;
int t, n, v[25];
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
return x * fl;
}
int main()
{
t = read();
while (t -- )
{
n = read(); int sg = 0;
while (n -- )
{
int m = read(), sg0 = 0, s = 20 - m + 1, tt = 0; memset(v, 0, sizeof(v));
while (m -- ) { int x = read(); v[x] = 1;}
for (int i = 1; i <= 20; i ++ )
{
if (v[i]) {tt ++ ; continue;}
s -- ; if (s & 1) sg0 ^= tt; tt = 0;
}
sg ^= sg0;
}
if (sg) puts("YES"); else puts("NO");
}
return 0;
}
威佐夫博弈
Description
有两堆石子,由两个人轮流取。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子(都至少要取一个)。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,求是否存在先手必胜的策略。
Solution
本题不满足函数的性质,故要换一种方式求解。
设这两堆石子分别有个且,那么后手必胜当且仅当
不会证,但是学习了定理:
对于两个无理数,若其满足,令两个集合,其中为正整数集。
则有。
用dp解决博弈问题
Description
有时博弈问题不是某种基本模型,且不能用函数求解,这时可以考虑(通常是要最大化/最小化答案)
Solution
抓住“当前这个人(能得到的)最大/最小值,等于总和减去该人进行这步操作后,另一人的操作值(所有可能情况里的最大/最小,因为另一人也想使答案最优)”
应用(P2964)
令为当前剩下第至第个硬币,当前这个人从第个硬币开始取个硬币所能获得的最大价值。
由于取完后就是另一个人取,他肯定会取价值最大的方案,因此可以列出状态转移方程:
其中
通过维护,将时间复杂度优化到
code
#include <bits/stdc++.h>
using namespace std;
int n, s[2005], f, g[2005][2005];
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
return x * fl;
}
int main()
{
n = read(); for (int i = 1; i <= n; i ++ ) {int x = read(); s[i] = s[i - 1] + x;}
for (int i = n; i >= 1; i -- )
{
for (int j = 1; j <= n - i + 1; j ++ )
{
f = s[n] - s[i - 1] - g[i + j][min(j << 1, n - i - j + 1)];
g[i][j] = max(g[i][j - 1], f);
}
}
printf("%d\n", g[1][2]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】