不平等博弈与超现实数(Surreal Number)
Hydroxythio · · 个人记录
一些闲话
大概是退役之前最后一次写博客了虽然就没写过几次。
请忽视上面的话。因为某些原因又写了点东西。
打模拟赛的时候遇到了一道不平等博弈的题,就顺便研究了一下。
由于本人才疏学浅,如果有一些错误或者疏漏还请见谅。
应该也可以在 Cooper233 巨佬的博客 里面看到这些内容(不知道他咕没咕)。
一些定义
不平等博弈
与平等博弈(公平组合游戏)相对。在
- 两人参与,轮流决策,双方均知道游戏的完整信息。
- 同一状态不可多次到达,无法继续决策的游戏者输,游戏在有限步内一定可以以非平局结束。
- 游戏者可以做出的决策不同。
超现实数(Surreal Number)
Warning:下面关于超现实数的内容大多是不严谨的,属于感性理解,对于
定义
我们可以这样理解超现实数:一个超现实数
超现实数存在一个与实数一一对应的关系,因此在下文中,我们将会借助实数来理解超现实数,并把
记
为了方便,在下文中如果出现实数集与超现实数之间的比较,我们均认为是这个实数集中的任意一个元素与这个超现实数对应的实数之间的比较。
偏序关系
假设现在我们有两个超现实数
达利函数
如下定义从实数映射到超现实数的达利函数
不难发现对于某些实数无法通过达利函数映射到超现实数,同样也不是所有超现实数都可以通过达利函数来表示,但是在
(重点)超现实数映射到实数
对于一个超现实数
首先还是记
- 若
l < 0 \wedge r > 0 ,那么有SN(x) = 0 。 - 若区间
[l,r] 之间存在一个整数,那么:- 若
0 \leq l ,那么SN(x) = \lfloor l + 1 \rfloor 。 - 否则一定有
r \leq 0 ,那么SN(x) = \lceil r - 1 \rceil 。
- 若
- 否则区间
[l,r] 之间不存在一个整数,那么SN(x) = \frac{k}{2^j} ,满足:-
- 在所有满足条件的
j,k 中,优先使j 最小,如果仍有多个,使k 最小。
-
下面我们不再以
举四个例子分别对应上述四种情况(按顺序排列):
超现实数的加法
现在我们有两个超现实数
令
不难发现这个定义非常抽象所以接下来我们尝试在用
令
再尝试把 显然我们不会真的去大力讨论所以抄结论得
(重点)超现实数与不平等博弈之间的关系
假设现在有两个玩家
假设我们用一个超现实数
假设玩家
那么
同理我们可以把
那么接下来,一个极其重要的结论:
- 若
SN(x) > 0 ,则该局面为玩家L 必胜。 - 若
SN(x) < 0 ,则该局面为玩家R 必胜。 - 否则一定有
SN(x)=0 ,该局面为后手必胜。
然后又是一个极其重要的结论:
如果一个不平等博弈可以分解为多个子游戏,那么这个不平等博弈的
然后就可以做题了。
一些例题
暂时只有一道,后续可能会加。
POJ 2931
简易题意
- 一个局面由四堆棋子构成,棋子有黑白两种颜色。
- 两位玩家
L,R 轮流操作。每轮操作者都必须选择一枚棋子,且L 只能选择白棋,R 只能选择黑棋。操作者选定一枚棋子后,可以把这枚棋子及其上方的所有棋子移走。不能操作者输掉游戏。 - 称一个局面对
L 有利,当且仅当这个在局面下,L 无论先手还是后手都能获胜。称一个子局面C 为给定的三堆棋子,并且一个局面可以表示为(C,T) ,其中T 是另一堆棋子。称一个子局面C_1 不比另一个子局面C_2 更劣,当且仅当对于任意的一堆棋子T ,若局面(C_2,T) 对L 有利,那么局面(C_1,T) 也 对L 有利。 - 给定两个子局面
C_1,C_2 ,子局面中每堆棋子均按从下到上的顺序给出,判断子局面C_1 是否不比子局面C_2 更劣。如果是,输出Yes,否则输出No。
解答
不难发现这是一个不平等博弈,并且一个局面可以分解为四个子游戏(每一堆棋子是一个子游戏)。
于是我们来考虑一堆棋子的
规定初始状态为
接下来加棋子的过程均从下往上考虑。
考虑加一个白棋,那么此时的
加
如果是加一个黑棋,那么
加
观察一下,如果从初始状态开始加
假设现在的局面的
再加一个黑棋:
再加一个白棋:
总结一下,在加了第一个异色棋子之后,再往后加不管是跟上一个同色还是异色,对
然后把两个子局面的 No,否则答案是 Yes。
时间复杂度
贴个码,注意没加多测:
#include <stdio.h>
typedef long long ll;
const int MAX_N = 50 + 5;
int len[3], a[MAX_N];
char s[MAX_N];
ll calc(ll N) {
int i;
ll res = 0, Base = 1ll << 50;
for (i = 1; i <= N && a[i] == a[1]; i ++)
if (a[i]) res += Base;
else res -= Base;
for (Base >>= 1; i <= N; i ++, Base >>= 1)
if (a[i]) res += Base;
else res -= Base;
return res;
}
ll solve() {
ll sn = 0;
scanf("%d%d%d", len, len + 1, len + 2);
for (int i = 0; i < 3; i ++) {
for (int j = 1; j <= len[i]; j ++) {
scanf("%s", s);
a[j] = s[0] == 'W';
}
sn += calc(len[i]);
}
return sn;
}
int main() {
ll sn0 = solve();
ll sn1 = solve();
if (sn0 < sn1) printf("No\n");
else printf("Yes\n");
return 0;
}