【笔记】简单博弈
前言
大半年前写的东西了,自己真的在走下坡路
例题
A , B进行游戏。A先开始,轮流将n减去{2,3,4,5,6}中的一个数,谁最后无法进行减法了,就输了。
给定n。A,B都采用最优策略,问A是否会赢。
状态
设f[i]表示当前的数是i的时候,对于当前的先手来说是否会赢
f[i]=true,则赢
f[i]=false,则输
转移
当先手A操作一次后,问题转移为了对于当前先手B,对(n-i)进行操作
必胜转移到必败,必败转移到必胜
就是说
从f[i]转移到的所有状态f[i-2],f[i-3]..f[i-6]如果都是必胜态,那么f[i]则为必败态
从f[i]转移到的所有状态f[i-2],f[i-3]..f[i-6]如果都是必败态,那么f[i]则为必胜态
初始化
f[0]和f[1]对于先手来说必败
f[0]=false,f[1]=false
f[2]则对于先手来说必胜,f[2]=true
碎碎念
前几天上数学课的时候老师讲了一个类似的题,当时想到了DP。
高级
当n%8=1或0时,必败。否则必胜
博弈DP的特征
博弈DP解决的是两人轮流操作,且没有平局的 #两人博弈游戏#
写代码的话一般是#人人为我#类型,即用其他状态向自己转移
更一般的,博弈没有固定搜索顺序,习惯用记忆化搜索
problem1【第一类,两人博弈类型】
状态
f[i][j]表示当前手上数字为i,上一个减去的数是j的时候是必胜还是必败
转移
f[i][j]转移到f[i-r][1~r],其中1<=r<=k*j
复杂度
O(n^3)
没有代码
problem2-1【第二类,组合两人博弈类型】
A,B两人游戏,现在有a1,a2,...an共n个数, 轮流操作,每次可以对任意一个数操作,最后谁无法操作谁就输了。操作为将这个数减去{1,2,3,4,5,6}中的一个。
范围:n<=\(10^5\),a_i<=\(10^5\)
分析
相当于有n个#二人博弈问题#,称之为#组合二人博弈问题#
状态
初始蒟蒻
设计一个n维的f[1][2][3]...[n],表示当前态
这玩意肯定不行,所以要用sg
mex运算
设S 表示一个非负整数集合。定义mex(S)为求出不属于集合S 的最小非负整数的运算。即:
mex(S) = min{x|x\(\in\) N, x$\notin\S}, 比如mex{0,2,3} = 1
sg函数(Sprague-Grundy 是两个人的名字)
sg[i]表示的是数字i这个状态的sg值
sg值:取出所有能转移到的sg值的前继状态集合{sg[1],sg[i-2]...sg[i-6]},则i的sg函数的值为这个集合的mex运算结果,即sg=mex{sg[1],sg[i-2]...sg[i-6]}
必败态的sg为0,必胜态的sg值为非零
对于这个题,sg[0]必败,所以s[0] = 0,s[1]的前继状态的集合为{s[0]},所以sg[1] = 1
sg[2]的前继状态集合为{sg[0] = 0,sg[1] = 1},sg[2] = 2
sg[3]的前继状态集合为{sg[0] = 0,sg[1] = 1,sg[2] = 2},sg[3] = 3
sg[4] = 4,sg[5] = 5,sg[6] = 6
sg[7]的状态集合为{sg[1] = 1, sg[2] = 2, sg[3] = 3,sg[4] = 4, sg[5] = 5, sg[6] = 6},sg[7] = 0
sg[8] = 1,sg[9] = 2
事实上,对于sg[8]和sg[9],先手必须把状态转移到sg[7],让下一个人必败
对于这个题,有sg值就可以不用n维了吗?不行。他还是这个样子:
sg[a1][a2]...[an]
sg定理
n个游戏的sg值 等于 每个游戏的sg值异或起来
sg(a1,a2...an) = sg(a1) xor sg(a2) ... xor sg(an)
所以我们分开讨论每个游戏,最后异或起来
没有代码
problem2-2——NIM游戏
n <= \(10^5\) a_i <= $10^9¥
problem3-1【第三类,可以转移到组合博弈】
n+1堆石子,最左边一堆石头有2012个,两个人分别进行操作。一次操作可以选取两堆不同的石堆分别增加或减少一个石子(一加一减,或给已经不剩石子的堆加一个都是允许的)。为了保证游戏会在有限步内结束,规定所选的两堆中右边的那一堆一定要包含奇数个石子,无路可走者输.问先手是否必胜?
problem3-2
problem3-3
必败态
除了最左边,每一堆都是偶数个石子,所以不讨论每一堆的实际个数,只讨论奇偶
a1,a2...an等于0或1
problem3-4
不关心石子个数,只关心奇偶
因为独立的是石子而不是石子队
因为我们的游戏单位是石子,两个石子的sg值相互抵消为0,所以只关心奇偶
NIM的游戏单位是石子堆
状态
sg[i]在第i堆的石子的sg值
转移
sg[i] = mex(sg[j]^sg[k])