公平组合游戏

不是写给自己看的。

ICG

考虑一类两个玩家的零和博弈游戏:

  1. 游戏有一个局面,双方轮流操作,每次操作转移到一个新局面。
  2. 能进行的操作与当前局面相关,与轮到哪一方操作无关(公平性)
  3. 无法操作的一方失败。
  4. 局面之间的转移无环。

这可以看做以局面为节点,转移边的有向无环图上沿边交替移动一个棋子。也就是 ICG 等价于其对应的 有向图游戏。

结论:任一 ICG 要么先手 存在必胜策略(简称先手必胜),要么后手 存在必胜策略(简称先手必败),两者恰有其一。

证明:

考虑归纳定义一个局面是先手必败的(P-position)当且仅当两者至少满足一个:

  1. 这个局面是终止局面(无法进一步操作 / 出度为 \(0\)
  2. 这个局面不能到达任何必败局面。

定义一个局面是先手必胜的(N-position)当且仅当:

  1. 这个局面可以到达至少一个必败局面。

相当于证明任何局面要么是 P-position,要么是 N-position。因为这个图是 DAG,可以从每个出度为 \(0\) 的点出发归纳证明。

一般有向图游戏

对于一般的有向图游戏,我们可以直接拓扑排序求出一个点是必胜还是必败局面,还不需要引入 SG 函数。题外话:这种思想也可以拿来求有环的类公平组合游戏,并判断平局。

Nim 游戏

局面:\(n\) 堆石子,数目分别为 \(a_1,a_2,\cdots,a_n\)

操作:任选一堆石子 \(i\),令 \(a_i\gets x\) 个,必须满足 \(0\le x< a_i\)

结论:先手必胜当且仅当初始 \(a_1,a_2,\cdots,a_n\) 的异或和不为 \(0\)。否则先手必败。

证明:

根据定义,证明一种判断 position 的性质的方法的正确性,只需证明三个命题:

  1. 这个判断将所有终止状态判为 P-position;
  2. 根据这个判断被判为 N-position 的局面一定可以移动到某个 P-position;
  3. 根据这个判断被判为 P-position 的局面无法移动到某个 P-position。

第一个命题显然,终止状态只有一个,就是全 \(0\),异或仍然是 \(0\)

第二个命题,即对于某个局面 \(a_1,a_2,\cdots,a_n\),若异或和不为 \(0\),一定存在某个合法的移动,将 \(a_i\) 改变成 \(a_i'\) 后满足异或和为 \(0\)。不妨设 \(a_1,a_2,\cdots,a_n\) 异或和为 \(k\),则一定存在某个 \(a_i\),它的二进制表示在 \(k\) 的最高位上是 \(1\)。这时 \(a_i\oplus k<a_i\) 一定成立,因为前者不满足。则我们可以将ai改变成 \(ai'=ai \oplus k\),此时异或和为 \(0\)

第三个命题,即即对于某个局面 \(a_1,a_2,\cdots,a_n\),若异或和为 \(0\),一定不存在某个合法的移动,将 \(a_i\) 改变成 \(a_i'\) 后满足异或和为 \(0\),否则 \(a_i=a_i'\)

用这种特殊的有向图游戏的思想,可以解决下面的问题。

SG 函数

考虑 有向图游戏的和:有多个 完全独立 的有向图游戏,它们共同构成一个新的游戏。这个游戏中:

  1. 局面即为所有有向图游戏的局面共同构成的状态。
  2. 操作为选择恰好一个可操作的有向图游戏做恰好一次操作。

因为局面变为了指数级,所以直接跑不再可行,必须借助相互独立的性质计算。


设有向图游戏 \(G\) 的一个局面 \(p\),定义

\(SG(p)=0\) 当且仅当 \(p\) 是一个必败局面。

\(SG(p)=x>0\) 当且仅当 \(\forall 0\le y<x\)\(p\) 可以转移到某个 \(SG(q)=y\) 的局面 \(q\);并且 不能转移到 \(SG(q)=x\) 的任何局面 \(q\)

发现这个东西其实和 Nim 游戏没有本质区别,只是把 \(a_i\) 换成了 \(SG(p)\)。但是有一个问题:没有保证 \(x>0\) 时不能转移到 \(SG(q)>x\) 的局面 \(q\)。但可以证明这是没有必要的,因为根据定义,若这一步转移到 \([0,x)\) 均不可获胜,下一步对方仍然可以转移回 \(SG(p')=x\)。注意 \(p'\ne p\),并非形成了环只是 \(SG\) 值不变。

于是得到结论:

  1. \(s\) 为有向图游戏 \(G\) 的起点,定义 \(SG(G)=SG(s)\)
  2. 游戏 \(\sum G\) 先手必胜,当且仅当所有 \(SG(G)\) 的异或和不为 \(0\);否则先手必败。

Depot

AGC016F Games on DAG

给定一个有向无环图 \(G=(V,E)\),定义 原游戏 为 从 \(1,2\) 两个节点出发形成的两个有向图游戏的和。求满足 \(E'\subseteq E\) 的所有 \(2^{|E|}\) 个生成子图 \(G'=(V,E')\) 中,使得原游戏先手必胜的数目。\(n\le15\)

等价于 \(sg_1\neq sg_2\)。这个难以求解,考虑改为 \(2^{|E|}\) 减去使得 \(sg_1=sg_2\) 的子图数目。


首先考虑求解 \(sg_1=0\) 的方案数。根据数据范围,设 \(f_P\) 表示 \(SG\) 值为 \(0\) 的集合为 \(P\subseteq V\) 情况下的方案数。另外

\[\forall 1\notin P, f_P=0 \]

这个东西不用 DP,可以 \(O(2^nm)\) 直接算,只需考虑四类边在子图的存在性:

首先考虑 \(P\) 内部,由定义这些边均不能存在。然后考虑从 \(P\) 连向 \(N\) 的边,由定义,这些边可以随便连。接下来是从 \(N\) 连向 \(P\) 的边,由定义每个 \(p\in N\) 至少应有一条这样的边存在。然后对于 \(N\) 内部 ,这些点之间可以随便连,因为只需要 \(SG\)\(0\) 就符合状态。直接乘法原理求出四类边的添加方案数。最后总方案数即为 \(\sum f\)

注意这时候我们考虑的 \(N\) 集合只限定了 \(\forall p\in N, SG(p) \ge 1\) 的条件,并没有考虑具体 \(SG\) 值。


考虑如何保证 \(sg_1=sg_2k\),这时候有人类智慧:

\(SG(p)=0,1,2,\cdots\) 依次加入。具体来说:考虑除去所有 \(P\) 中节点,得到导出子图 \(G[N]\),容易证明其中每个节点 相比原来此节点 \(SG\) 值恰好减少 \(1\)。所以我们可以做 \(O(n)\) 轮 DP 解决。

\(g_S\) 表示只考虑点集 \(S\in V\),要求 \(sg_1=sg_2\) 的方案数。其中

\[\forall [1\in S]\neq[2\in S], g_S=0 \]

注意到这个条件使得 \(sg_1=sg_2\) 相等(因为两点在同一轮被加入)。

对于 \(g_S\),每次枚举子集 \(N\),从 \(g_N\) 转移。然后按照前述算法统计\(G[P],cross(P,N),cross(N,P)\) 的边,对于 \(G[N]\) 中的边,它就相当于只考虑这个导出子图G[N]的满足条件的方案数,即子问题 \(g_N\)

最后答案即为 \(g_V\)。复杂度 \(O(3^nn)\)

#include <bits/stdc++.h>
#define popc __builtin_popcount
#define ctz __builtin_ctz

typedef long long ll;
const int maxn = 18, maxj = 1 << maxn, mod = 1000000007;

int n, m, all;
int e[maxn], f[maxj];

int main() {
	int i, j, u, v, k, real, N, P, sum = 1;
	scanf("%d%d", &n, &m), all = (1 << n) - 1;
	for (i = 0; i < m; ++i)
		scanf("%d%d", &u, &v), e[--u] |= 1 << --v, sum = sum * 2 % mod;
	for (f[0] = 1, i = 2; i <= all; i += 2) // 保证 1 不在其中
		// 枚举子集
		for (j = i; ; j = (j - 1) & i) {
			ll res = 1;
			real = i + (i >> 1 & 1); // 若 2 在其中,加入 1
			N = j + (j >> 1 & 1), P = real & ~N;
			// 枚举其中节点,转移。
			for (k = real; k; k &= k - 1)
				v = __builtin_ctz(k), res = res * (N >> v & 1 ? (1 << __builtin_popcount(e[v] & P)) - 1 : 1 << __builtin_popcount(e[v] & N)) % mod;
			f[i] = (f[i] + res * f[j]) % mod;
			if (!j) break;
		}
	sum -= f[all - 1], printf("%d\n", sum + (sum >> 31 & mod));
	return 0;
}
posted @ 2023-08-24 21:26  音街ウナ  阅读(42)  评论(1)    收藏  举报