浅谈博弈论

我们认为在当前局面下玩家无法操作的局面是失败局面

例题1:引入

有一堆 n n n 个石子 , 现给定集合 { s 1 . . . s k } \lbrace s_1...s_k\rbrace {s1...sk} , 每次可以取 s i ( 1 ≤ i ≤ k ) s_i(1\le i\le k) si(1ik) 颗 , 问先手是否必胜 ( n , k ≤ 1000 ) (n,k\le 1000) (n,k1000)

我们记 f x f_x fx 表示 x x x 颗石子的情况下 , 先手是否必胜

那么只要存在 i i i 使得 f x − s i f_{x-s_i} fxsi f a l s e false false , 先手就可以拿走 s i s_i si 颗石子 , 使对手遇到 f x − s i f_{x-s_i} fxsi 的局面 , 从而取胜

int dfs(int x)
{
	if(x==0) return 0;
	if(mem[x]) return f[x];
	mem[x] = 1;
	for(int i=1;i<=k;i++)
	{
		if(x>=s[i])  f[x] |= (!dfs(x-s[i]));
	}
	return f[x];
}

cout << dfs(n);

我们也可以将其看作是一个只有一个起点的有向图游戏 , 一开始是 n n n , 边权为 − s i -s_i si

有向图游戏 : 在一个 D A G DAG DAG 中,只有一个起点,上面有一个棋子,两个玩家轮流沿着有向边推动棋子,不能走的玩家判负

Nim博弈

例题2 : Nim博弈模板

Nim游戏 : n n n 堆石子 , 每堆 a i a_i ai 个 , 每次从第 i i i 堆取 1 1 1 a i a_i ai 个石子 , 问先手是否必胜 ( n , s i ≤ 1 0 4 ) (n,s_i\le10^4) (n,si104)

若我们延续 例题1 的思路 , 发现时间复杂度和空间复杂度都会很高 , 而此题有一个结论 :

当且仅当 a 1 ∧ a 2 ∧ . . . . . a n = 0 a_1\land a_2\land .....a_n=0 a1a2.....an=0 时 , 先手无必胜策略

证明 :

  • 结论1:
    a 1 ∧ a 2 ∧ . . . . . a n = 0 a_1\land a_2\land .....a_n=0 a1a2.....an=0 时 , 无论怎样取 , 其异或和必不等于 0 0 0

    证明1:
    反证法 : 假设存在将第 i i i 堆从 a i a_i ai 取成 a i ′ a_i' ai 的方案使得异或和为 0 0 0

    那么 , a 1 ∧ . . . ∧ a i ′ ∧ . . . ∧ a n = 0 a_1\land ...\land a_i' \land...\land a_n=0 a1...ai...an=0 a 1 ∧ . . . ∧ a i ∧ . . . ∧ a n = 0 a_1\land ...\land a_i \land...\land a_n=0 a1...ai...an=0 , 得 a i = a i ′ a_i=a_i' ai=ai 即取了 0 0 0 颗 , 不合题意 , 矛盾

  • 结论2:
    a 1 ∧ a 2 ∧ . . . . . a n ≠ 0 a_1\land a_2\land .....a_n\ne 0 a1a2.....an=0 时 , 总存在取法使得异或和变为 0 0 0

    证明2:有
    a 1 ∧ a 2 ∧ . . . . . a n = x a_1\land a_2\land .....a_n= x a1a2.....an=x

    我们设 x x x 二进制下最高位 1 1 1 在第 k k k 位 , 那么至少存在一堆石子 a i a_i ai 的第 k k k 位为 1 1 1 , 那么 a i ∧ x < a i a_i\land xaix<ai , 因此一定存在一个将 a i a_i ai 取成 a i ∧ x a_i\land x aix 的方案从而使得异或和变为 0 0 0

因此在 a 1 ∧ a 2 ∧ . . . . . a n ≠ 0 a_1\land a_2\land .....a_n\ne 0 a1a2.....an=0 的局面下 , 先手可将局面变为异或和为 0 0 0 的局面 , 而后手只能又将异或和变为非零 , 一直循环至全部取完

而全部取完时, a 1 ∧ a 2 ∧ . . . . . a n = 0 a_1\land a_2\land .....a_n=0 a1a2.....an=0 , 为必败局面 , 而只有后手才会遇到异或和为零的局面 , 因此先手在此情况下必胜 , 证毕.

	cin >> n;
	int sum = 0;
	for(int i=1;i<=n;i++) 
	{
		cin >> a[i];
		sum ^= a[i];
	}
	if(!sum) puts("No"); 
	else puts("Yes");

例题3: 取火柴(Nim博弈)

此题要求输出先手取胜策略的第一步

如上文分析 : 若 a 1 ∧ a 2 ∧ . . . . . a n = x a_1\land a_2\land .....a_n=x a1a2.....an=x , 先手第一次取后应使得异或和变为 0 0 0 , 即将某个 a i a_i ai 取成 a i ∧ x a_i\land x aix

根据题目要求 , 找到 i i i 最小的 a i ∧ x < a i a_i\land xaix<ai 即可


SG定理

  • 定义1: m e x mex mex

    m e x ( S ) = m i n { x } mex(S)=min\lbrace x\rbrace mex(S)=min{x} ( x x x 不属于 S S S , x x x 为非负整数)

  • 定义2: 有向图游戏

    例题1 中已经阐释过 , 例题1 就是一个只有一个起点的有向图游戏

  • 定义3: SG函数

    对于状态 x x x 和他的所有 k k k 个后继状态 y 1 . . . y k y_1...y_k y1...yk , S G ( x ) = m e x { S G ( y 1 ) , . . . . S G ( y k ) } SG(x)=mex\lbrace SG(y_1),....SG(y_k)\rbrace SG(x)=mex{SG(y1),....SG(yk)}

SG定理 而对于由 n n n 个有向图游戏组成的组合游戏,设它们的起点分别为: s 1 , s 2 , . . . . s n s_1,s_2,....s_n s1,s2,....sn , 当且仅当 S G ( s 1 ) ∧ S G ( s 2 ) ∧ . . . ∧ S G ( s n ) ≠ 0 SG(s_1)\land SG(s_2)\land ...\land SG(s_n)\ne 0 SG(s1)SG(s2)...SG(sn)=0 时 , 先手必胜

例题4 :SG定理模板

n n n 堆石子 , 分别为 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an , 给定 { s 1 . . s k } \lbrace s_1..s_k\rbrace {s1..sk} 每次只能取 s i s_i si

看作是一个 n n n 个起点的有向图游戏 , 考虑使用 SG定理 , 求出每个起点的 S G SG SG 即可 ( 这里是 S G ( a 1 ) , S G ( a 2 ) . . . S G ( a 3 ) SG(a_1),SG(a_2)...SG(a_3) SG(a1),SG(a2)...SG(a3) )

int dfs(int x)
{
	if(x==0) return 0; 
	if(mem[x]) return SG[x];
	mem[x] = true;
	bool v[105]; memset(v,0,sizeof(v));
	for(int i=1;i<=k;i++)
	{
		if(x>=s[i]) v[dfs(x-s[i])] = 1;
	}
	int i = 0; while(v[i++]);
	return SG[x] = i-1; 
}

你可能感兴趣的:(学习笔记,题解,算法)