By zhongzijun \text{zhongzijun} zhongzijun
博弈论又被称为对策论(Game Theory)既是现代数学的一个新分支,也是运筹学的一个重要学科。
博弈论主要研究公式化了的激励结构间的相互作用。是研究具有斗争或竞争性质现象的数学理论和方法。 博弈论考虑游戏中的个体的预测行为和实际行为,并研究它们的优化策略。生物学家使用博弈理论来理解和预测进化论的某些结果。
博弈论已经成为经济学的标准分析工具之一。在金融学、证券学、生物学、经济学、国际关系、计算机科学、政治学、军事战略和其他很多学科都有广泛的应用。
先来观察两个游戏。
甲乙两人面对若干堆石子,其中每一堆石子的数目可以任意确定。
例如 【 图 1 】 【 图 1 】 【图1】 所示的初始局面:共 n = 3 n=3 n=3 堆,其中第一堆的石子数 a 1 = 3 a1=3 a1=3 ,第二堆石子数 a 2 = 3 a2=3 a2=3 ,第三堆石子数 a 3 = 1 a3=1 a3=1 。两人轮流按下列规则取走一些石子,游戏的规则如下:
每一步应取走至少一枚石子;
每一步只能从某一堆中取走部分或全部石子;
如果谁无法按规则取子,就输了。
甲乙双方事先约定一个数 m m m ,并且每次取石子的数目不能超过 m m m 个,其余规则同 游戏 A 。
我们关心的是,对于一个初始局面,究竟是 先 行 者 ( 甲 ) 先行者(甲) 先行者(甲) 有必胜策略,还是 后 行 者 ( 乙 ) 后行者(乙) 后行者(乙) 有必胜策略。
下面,我们从简单入手,先来研究研究这个游戏的一些性质。
用一个 n n n 元组 ( a 1 , a 2 , … , a n ) (a1, a2, …, an) (a1,a2,…,an) ,来描述游戏过程中的一个局面。
( a 1 , a 2 , … , a n ) + ( b 1 , b 2 , … , b m ) = ( a 1 , a 2 , … , a n , b 1 , b 2 , … , b m ) (a_1, a_2, …, a_n) + (b_1, b_2, …, b_m) = (a_1, a_2, …, a_n, b_1, b_2, …, b_m) (a1,a2,…,an)+(b1,b2,…,bm)=(a1,a2,…,an,b1,b2,…,bm) 。
对于 局面A , B , S ,若 S = A + B S=A+B S=A+B ,则称局面 S 可以分解为“子局面” A 和 B 。
局 面 ( 3 , 3 , 1 ) 局面(3, 3, 1) 局面(3,3,1) 可以分解为 ( 3 , 3 ) (3, 3) (3,3) 和 ( 1 ) (1) (1) 。
如果初始局面可以分成两个相同的“子局面”,则乙有必胜策略。
对于局面S,若先行者有必胜策略,则称“ S胜 ”。
对于局面S,若后行者有必胜策略,则称“ S负 ”。
若 A = ( 1 ) A=(1) A=(1) , B = ( 3 , 3 ) B=(3, 3) B=(3,3) , C = ( 2 , 2 , 5 , 5 , 5 , 5 , 7 , 7 ) C=(2, 2, 5, 5, 5, 5, 7, 7) C=(2,2,5,5,5,5,7,7) ,则我们称 A 胜 A胜 A胜 , B 负 B负 B负 , C 负 C负 C负 。
如果 局 面 S 局面S 局面S 胜,则必存在取子的方法 S → T S→T S→T ,且 T 负 T负 T负 。
如果 局 面 S 局面S 局面S 负,则对于任意取子方法 S → T S→T S→T ,有 T 胜 T胜 T胜 。
设 初 始 局 面 S 初始局面S 初始局面S 可以分解成两个子局面 A A A 和 B B B (分解理论) 。
若 A A A 和 B B B 一胜一负,则 S 胜 S胜 S胜 。
若 A A A 负 B B B 负,则 S 负 S负 S负 。
若 A A A 胜 B B B 胜,则 有 时 S 胜 , 有 时 S 负 有时S胜,有时S负 有时S胜,有时S负 。
如果 S = A + C + C S=A+C+C S=A+C+C ,则 S S S 的胜负情况 与 A A A 相同。
即当 S = A + B S=A+B S=A+B 且 B B B 负时 S S S 的胜负情况与 A A A 相同。
【 图 1 】所示的初始局面 ( 3 , 3 , 1 ) = ( 3 ) + ( 3 ) + ( 1 ) (3, 3, 1) = (3) + (3) + (1) (3,3,1)=(3)+(3)+(1) ,与局面 ( 1 ) (1) (1) 的 胜 负 情 况 相 同 胜负情况相同 胜负情况相同 。
请认真思考一下这是为什么。
图1中所示的初始局面 ( 3 , 3 , 1 ) (3, 3, 1) (3,3,1) 是“胜”局面,甲有必胜策略。
称一个石子也没有的局面为“空局面”。
空局面是“负”局面。
如果 局 面 S 局面S 局面S 中,存在两堆石子,它们的数目相等。用 T T T 表示从 S S S 中把这两堆石子拿掉之后的局面,则称“ S 可 以 简 化 为 T S可以简化为T S可以简化为T ”。
局面 ( 2 , 2 , 2 , 7 , 9 , 9 ) (2, 2, 2, 7, 9, 9) (2,2,2,7,9,9) 可以简化为 ( 2 , 2 , 2 , 7 ) (2, 2, 2, 7) (2,2,2,7) ,还可以进一步简化为 ( 2 , 7 ) (2, 7) (2,7) 。
一个局面的胜负情况,与其简化后的局面相同。
例如三个局面 ( 2 , 2 , 2 , 7 , 9 , 9 ) (2, 2, 2, 7, 9, 9) (2,2,2,7,9,9) 、 ( 2 , 2 , 2 , 7 ) (2, 2, 2, 7) (2,2,2,7) 和 ( 2 , 7 ) (2, 7) (2,7) ,胜负情况都相同。
不能简化的局面称为“最简局面”。
局面 ( 2 , 7 ) (2, 7) (2,7) 是最简局面。
最简局面中不会有两堆相同的石子,故可以用一个集合来表示最简局面。
最简局面 ( 2 , 7 ) (2, 7) (2,7) 可以用 集 合 2 , 7 集合{2, 7} 集合2,7 来表示。
如果只关心局面的胜负,则一个局面可以用一个集合来描述。
图1所示的局面 ( 3 , 3 , 1 ) (3, 3, 1) (3,3,1) ,可以用 集 合 1 集合{1} 集合1 来描述。
如果用搜索(博弈树)的方法来解这个游戏,则采用集合来表示一个局面,比采用多元组来表示一个局面,搜索量将有所减少,但时间复杂度仍然很高。
能不能进一步简化一个局面的表示呢?
注意,这里的二进制加法指的是不进位的二进制加法。
二进制数的加法 VS 局面的加法
大 写 字 母 A B 大写字母AB 大写字母AB 表示 局 面 局面 局面 , 小 写 字 母 a b 小写字母ab 小写字母ab 表示二进制数。
若 A 和 B 相 同 A和B相同 A和B相同 ,则 A + B A+B A+B 负;若 a 和 b 相 等 a和b相等 a和b相等 ,则 a + b 为 0 a+b为0 a+b为0 。
若 A 胜 B 负 A胜B负 A胜B负 ,则 A + B 胜 A+B胜 A+B胜 ;若 a ≠ 0 a≠0 a=0 且 b = 0 b=0 b=0 ,则 a + b ≠ 0 a+b≠0 a+b=0 。
若 B 胜 A 负 B胜A负 B胜A负 ,则 A + B 胜 A+B胜 A+B胜 ;若 b ≠ 0 b≠0 b=0 且 a = 0 a=0 a=0 ,则 a + b ≠ 0 a+b≠0 a+b=0 。
若 A 负 B 负 A负B负 A负B负 ,则 A + B 负 A+B负 A+B负 ;若 a = 0 a=0 a=0 且 b = 0 b=0 b=0 ,则 a + b = 0 a+b=0 a+b=0 。
若 A 胜 B 胜 A胜B胜 A胜B胜 ,则 A + B 有 时 胜 , 有 时 负 A+B有时胜,有时负 A+B有时胜,有时负 。
若 a ≠ 0 a≠0 a=0 且 b ≠ 0 b≠0 b=0 ,则有时 a + b ≠ 0 a+b≠0 a+b=0 ,有时 a + b = 0 a+b=0 a+b=0 。
……
如果用 二 进 制 数 s 二进制数s 二进制数s 来表示一个 局 面 S 局面S 局面S 的 胜 或 负 胜或负 胜或负 , S 胜 S胜 S胜 则 s ≠ 0 s≠0 s=0 , S 负 S负 S负 则 s = 0 s=0 s=0 。
局面的加法,与二进制数的加法,性质完全相同。
能否用一个二进制数,来表示一个局面呢?
用 KaTeX parse error: Expected 'EOF', got '#' at position 3: 符号#̲S ,表示局面S所对应的二进制数。
如果 局 面 S 局面S 局面S 只有一堆石子,则用这一堆石子数目所对应的 二 进 制 数 二进制数 二进制数 来表示 S S S 。
例如 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲(5)=5=101 。
若局面 S = A + B S=A+B S=A+B ,则 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S=#A+#B 。
局面 ( 3 , 3 ) = ( 3 ) + ( 3 ) (3, 3)=(3)+(3) (3,3)=(3)+(3) ,所以 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲(3, 3)=#(3)+#(3… 。
局面 ( 3 , 3 , 1 ) = ( 3 , 3 ) + ( 1 ) (3, 3, 1)=(3, 3)+(1) (3,3,1)=(3,3)+(1) ,所以 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲(3, 3, 1)=#(3, … 。
函数f :若 局 面 S 局面S 局面S 只有一堆石子,设 S = a 1 S={a1} S=a1 ,则 KaTeX parse error: Expected 'EOF', got '#' at position 7: f(a1)=#̲S ,即 KaTeX parse error: Expected 'EOF', got '#' at position 7: f(a1)=#̲(a1) 。
对于 游 戏 A 游戏A 游戏A 来说, KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲(5)=101 ,所以 f ( 5 ) = 101 f(5)=101 f(5)=101 。
对于 游 戏 A 游戏A 游戏A 来说, f ( x ) f(x) f(x) 就是 x x x 所对应的 二 进 制 数 二进制数 二进制数 。换句话说, f ( x ) = x f(x)=x f(x)=x 。
游 戏 B 游戏B 游戏B 的 f 函 数 f函数 f函数 则为 : f ( x ) = x m o d ( m + 1 ) f(x)=x mod (m+1) f(x)=xmod(m+1) 。
设局面 S = ( a 1 , a 2 , … , a n ) S=(a1, a2, …, an) S=(a1,a2,…,an) ,即 S = ( a 1 ) + ( a 2 ) + … + ( a n ) S=(a1)+(a2)+…+(an) S=(a1)+(a2)+…+(an) ,则 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S=f(a1)+f(a2)+…… 。例如 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲(3, 3, 1)=#((3)… 。
对于局面S,若#S=0,则S负;若#S≠0,则S胜。
二进制数 a, b ,若 a + b = 0 ,当且仅当 a = b 。
二进制数 a, b, s ,若 a + b = s ,则 a = b + s 。
二进制数 a 1 + a 2 + … + a n = p ≠ 0 a1+a2+…+an=p≠0 a1+a2+…+an=p=0 ,则 必 存 在 k 必存在 k 必存在k ,使得 a k + p < a k ak+p < ak ak+p<ak 。
因为 p ≠ 0 p≠0 p=0 ,所以 p p p 的最高位是 1 1 1 ;
设 p p p 的 最 高 位 最高位 最高位 是 第 q 位 第q位 第q位 ;
至 少 存 在 一 个 k 至少存在一个k 至少存在一个k ,使得 a k ak ak 的 第 q 位 第q位 第q位 也是 1 1 1 ;
a k + p ak+p ak+p 的 第 q 位 第q位 第q位 为 0 0 0 ,所以 a k + p < a k ak+p < ak ak+p<ak 。
若 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S=0 ,则无论先行者如何取子 S → T S→T S→T ,都有 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲T≠0 。
先行者只能从某一堆中取若干石子,不妨设他选择的就是第1堆;
设先行者从第1堆中取了x个石子,用T表示取完之后的局面;
设S=(a1, a2, …, an),则T=(a1–x, a2, …, an);
KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S=f(a1)+#(a2, ……,故f(a1)=#(a2, …, an);
KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲T=f(a1–x)+#(a2,…;
x>0→f(a1)≠f(a1–x)→f(a1)+f(a1–x)≠0→#T≠0。
若 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S≠0 ,则先行者必然存在一种取子方法 S → T S→T S→T ,且 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲T=0 。
设 S = ( a 1 , a 2 , … , a n ) S=(a1, a2, …, an) S=(a1,a2,…,an) , KaTeX parse error: Expected 'EOF', got '#' at position 3: p=#̲S=f(a1)+f(a2)+…… ;
因为 p ≠ 0 p≠0 p=0 ,所以 必 然 存 在 k 必然存在k 必然存在k ,使得 f ( a k ) + p < f ( a k ) f(ak)+p
先行者将 第 1 堆 第1堆 第1堆 的石子的数目从 a 1 a1 a1 变成 x x x ,用 T T T 表示 这 个 局 面 这个局面 这个局面 ;
KaTeX parse error: Expected 'EOF', got '#' at position 3: p=#̲S=f(a1)+#(a2, ……,故 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲(a2, …, an)+2f(… (两个相同的数相加等于 0 );
KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲T=f(x)+#(a2, …,… 。
若 S S S 是 空 局 面 空局面 空局面 ,则 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S=0 。
若 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S=0 ,则 S 负 S负 S负 ;若 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S≠0 ,则 S 胜 S胜 S胜 。
KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲(1, 2, 3)=01+10…,故 局 面 ( 1 , 2 , 3 ) 负 局面(1, 2, 3)负 局面(1,2,3)负 。
KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲(1, 2, 3, 4)=00…,故 局 面 ( 1 , 2 , 3 , 4 ) 胜 局面(1, 2, 3, 4)胜 局面(1,2,3,4)胜 。
对于 游 戏 A 游戏A 游戏A 来说,任意的一个 初 始 局 面 S = ( a 1 , a 2 , … , a n ) 初始局面S=(a1, a2, …, an) 初始局面S=(a1,a2,…,an) ,我们把这里的 a i ai ai 都看成是 二 进 制 数 二进制数 二进制数 。令 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S=a1+a2+…+an 。若 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S≠0 ,则 先 行 者 ( 甲 ) 先行者(甲) 先行者(甲) 有必胜策略;否则 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S=0 ,这时 后 行 者 ( 乙 ) 后行者(乙) 后行者(乙) 有必胜策略。
下面把这个结论推广到 游 戏 B 游戏B 游戏B 。
对于任意初始局面 S = ( a 1 , a 2 , … , a n ) S=(a1, a2, …, an) S=(a1,a2,…,an) ,令 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S=f(a1)+f(a2)+…… 。
若 KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲S≠0 ,则 先 行 者 ( 甲 ) 先行者(甲) 先行者(甲) 有必胜策略;否则 后 行 者 ( 乙 ) 后行者(乙) 后行者(乙) 有必胜策略。
类似 游 戏 A 游戏A 游戏A 的证明。
游 戏 B 游戏B 游戏B 的解法与 游 戏 A 游戏A 游戏A 十分类似。这是因为两个游戏的规则相当类似。
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
关键在于判断初始局面是不是奇异局势。是则先手输,否则先手赢。
定义:对于形如 ( a k , b k ) ( a k ≤ b k , k = 0 , 1 , 2 , … , n ) (a_k,b_k)(a_k ≤ b_k ,k=0,1,2,…,n) (ak,bk)(ak≤bk,k=0,1,2,…,n) , a k a_k ak 是前面没有出现过的最小的自然数 , b k = a k + k b_k=a_k+k bk=ak+k 的局势叫做奇异局势。
例子:例如 ( 0 , 0 ) (0,0) (0,0) 、 ( 1 , 2 ) (1,2) (1,2) 、 ( 3 , 5 ) (3,5) (3,5) 、 ( 4 , 7 ) (4,7) (4,7) 、 ( 6 , 10 ) (6,10) (6,10) 、 ( 8 , 13 ) (8,13) (8,13) 、 ( 9 , 15 ) (9,15) (9,15) 、 ( 11 , 18 ) (11,18) (11,18) 、 ( 12 , 20 ) (12,20) (12,20) 都是奇异局势。
判断:当 min ( a , b ) = 1 2 ∣ b − a ∣ ( 5 + 1 ) \min(a,b)=\frac{1}{2}|b-a|(\sqrt{5}+1) min(a,b)=21∣b−a∣(5+1) 时,局面 ( a , b ) (a,b) (a,b) 是奇异局势。
性质
任何自然数都包含在一个且仅有一个奇异局势中。
由于 a [ k ] a[k] a[k] 是未在前面出现过的最小自然数,所以有 a [ k ] > a [ k − 1 ] a[k] > a[k-1] a[k]>a[k−1] ,而 b [ k ] = a [ k ] + k > a [ k − 1 ] + k > a [ k − 1 ] + k − 1 = b [ k − 1 ] > a [ k − 1 ] b[k]= a[k] + k > a[k-1] + k > a[k-1] + k - 1 = b[k-1] > a[k-1] b[k]=a[k]+k>a[k−1]+k>a[k−1]+k−1=b[k−1]>a[k−1] 。所以 性 质 1 性质1 性质1 成立。
任意操作都可将奇异局势变为非奇异局势。
事实上,若只改变奇异局势 ( a [ k ] , b [ k ] ) (a[k],b[k]) (a[k],b[k]) 的某一个分量,那么另一个分量不可能在其他奇异局势中,所以必然是非奇异局势。如果使 ( a [ k ] , b [ k ] ) (a[k],b[k]) (a[k],b[k]) 的两个分量同时减少,则由于其差不变,且不可能是其他奇异局势的差,因此也是非奇异局势。
采用适当的方法,可以将非奇异局势变为奇异局势。
假设面对的局势是 ( a , b ) (a,b) (a,b) ,若 b = a b = a b=a ,则同时从两堆中取走 a a a 个物体,就变为了奇异局势 ( 0 , 0 ) (0,0) (0,0) ;如果 a = a [ k ] , b > b [ k ] a = a[k] , b > b[k] a=a[k],b>b[k] 那么,取走 ( b − b [ k ] ) (b - b[k]) (b−b[k]) 个物体,即变为奇异局势;如果 a = a [ k ] , b < b [ k ] a = a[k] , b < b[k] a=a[k],b<b[k] 则同时从两堆中拿走 a − a [ b − a ] a-a[b-a] a−a[b−a](注:这里 ( b − a ) (b-a) (b−a) 是 a a a 的下标) 个物体变为奇异局势( a [ b − a ] , b − a + a [ b − a ] a[b-a] , b-a+a[b-a] a[b−a],b−a+a[b−a] );如果 a > a [ k ] , b = a [ k ] + k a > a[k] , b= a[k] + k a>a[k],b=a[k]+k 则从第一堆中拿走多余的数量 ( a − a [ k ] ) (a - a[k]) (a−a[k]) 即可;如果 a < a [ k ] , b = a [ k ] + k a < a[k] , b= a[k] + k a<a[k],b=a[k]+k ,分两种情况,第一种, a = a [ j ] ( j < k ) a=a[j] (j < k) a=a[j](j<k) 从第二堆里面拿走 ( b − b [ j ] ) (b - b[j]) (b−b[j]) 即可;第二种, a = b [ j ] ( j < k ) a=b[j] (j < k) a=b[j](j<k) 从第二堆里面拿走 ( b − a [ j ] ) (b - a[j]) (b−a[j]) 即可。
s g 函 数 sg函数 sg函数 是定义在组合游戏上的函数,用 g ( X ) g(X) g(X) 表示 状 态 X 状态X 状态X 的函数值, F ( x ) F(\text{x}) F(x) 表示 局 面 X 局面X 局面X 的后继状态,即如果能够通过 局 面 X 局面X 局面X 直接到达 局 面 Y 局面Y 局面Y ,那么 Y ∈ F ( x ) Y \in F(\text{x}) Y∈F(x) 。它的定义如下:
mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如 mex{0,1,2,4}=3 、 mex{2,3,5}=0 、 mex{}=0 。
“?”符号指的是补集。补集一般指绝对补集,即一般地,设 S 是一个集合, A 是 S 的一个子集,由 S 中所有不属于 A 的元素组成的集合,叫做子集 A 在 S 中的绝对补集。在集合论和数学的其他分支中,存在补集的两种定义:相对补集和绝对补集。
g ( X ) = mex ( F ( x ) ) = min ( n ∣ n ∈ ? N F ( x ) ) g(X)=\text{mex}(F(\text{x})) =\min(n|n∈?NF(\text{x})) g(X)=mex(F(x))=min(n∣n∈?NF(x))
对于 X = X 1 + X 2 + . . . + X n X=X_1+X_2+...+X_n X=X1+X2+...+Xn ,有 g ( X ) = g ( X 1 ) ⊕ g ( X 2 ) ⊕ . . . ⊕ g ( X n ) g(X)=g(X_1)⊕g(X_2)⊕...⊕g(X_n) g(X)=g(X1)⊕g(X2)⊕...⊕g(Xn) 。
令 b = g 1 ( X 1 ) ⊕ g 2 ( X 2 ) ⊕ . . . ⊕ g n ( X n ) b=g1(X_1)⊕g2(X_2)⊕...⊕gn(X_n) b=g1(X1)⊕g2(X2)⊕...⊕gn(Xn) ,那么我们需要证明:
1)对于任意 a ∈ N a∈N a∈N 且 a < b a < b a<b,一定存在 X ′ ∈ F ( X ) X'∈F(X) X′∈F(X) 使 g ( X ′ ) = a g(X')=a g(X′)=a 。
2)对于任意 X ′ ∈ F ( X ) X'∈F(X) X′∈F(X) ,那么 G ( X ′ ) ≠ b G(X')≠b G(X′)=b 。
对于任意 X ′ ∈ F ( X ) X'∈F(X) X′∈F(X) ,那么 G ( X ′ ) ≠ b G(X')≠b G(X′)=b 。
对于一个任意的的 X X X 存在 X ’ ∈ F ( X ) X’∈F(X) X’∈F(X) 使 g ( X ’ ) = b g(X’)=b g(X’)=b 。
那么令 X ’ = ( X 1 , … , X i ’ , … , X n ) , g ( X ’ ) = g 1 ( X 1 ) ⊕ … g i ( X i ’ ) … g n ( X n ) = b X’=(X_1,…,X_i’,…,X_n),g(X’)=g1(X_1)⊕ …gi(X_i’)…gn(X_n)=b X’=(X1,…,Xi’,…,Xn),g(X’)=g1(X1)⊕…gi(Xi’)…gn(Xn)=b 。
因此 g i ( X i ’ ) = g i ( X i ) gi(X_i’)=gi(X_i) gi(Xi’)=gi(Xi) ,与SG函数的定义矛盾,得证。
下面就让我们看一下 S G 函 数 SG函数 SG函数 的应用。
有一堆石子共 n n n 个石子,两个人轮流取,每次都只能取 2 的幂次方的个数的石子,取到最后一颗石子的人是胜者。给出你 n n n 的值,请你判断先手是否有必胜策略。
1 ≤ n ≤ 1 0 3 1 \leq n \leq 10^3 1≤n≤103 。
题目来源:HDU 1847(Good Luck in CET-4 Everybody!)
//HDU 1847 -- Good Luck in CET-4 Everybody!
#include
#include
#define MAXN 1010
#define MAXM 11
using namespace std;
int sg[MAXN], f[MAXM];
bool Hash[MAXN];
void getSG(int m)
{
memset(sg, 0, sizeof(sg));
for (int i = 1; i < MAXN; i++)//枚举石子的个数
{
memset(Hash, false, sizeof(Hash));
for (int j = 0; j < m && f[j] <= i; j++)
Hash[sg[i-f[j]]] = true;//枚举每次拿走的个数并标记
for (int j = 0; j < MAXN; j++)
{
if (!Hash[j])
{
sg[i] = j;//找到这个F[](该状态可以达到的状态)中不存在的最小的数
break;
}
}
}
}
int main()
{
int n, num = 1;
for (int i = 0; i < MAXM; num <<= 1, i++)
f[i] = num;//这里的F数组就是可以移动的步数,每次都是2的幂次
getSG(MAXM);
for(int i=1;i<=100;i++)
{
printf("%d ",sg[i]);
}
return 0;
while (cin >> n)
{
if (sg[n])
cout << "Kiki" << endl;
else
cout << "Cici" << endl;
}
return 0;
}
可以通过 模拟 和 下面的两句话 来理解例题的 代码 。
此外,求 SG函数 的值还可以用深搜来求,但是没有前面所说的方法那么方便。
//注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍
//n是集合s的大小 S[i]是定义的特殊取法规则的数组
int s[110],sg[10010],n;
int SG_dfs(int x)
{
int i;
if(sg[x]!=-1)
return sg[x];
bool vis[110];
memset(vis,0,sizeof(vis));
for(i=0;i<n;i++)
{
if(x>=s[i])
{
SG_dfs(x-s[i]);
vis[sg[x-s[i]]]=1;
}
}
int e;
for(i=0;;i++)
if(!vis[i])
{
e=i;
break;
}
return sg[x]=e;
}
有三堆石子共 n , m , p n,m,p n,m,p 个石子,两个人轮流取,每次都只能取斐波那契数列上的个数的石子,取到最后一颗石子的人是胜者。给出你 n , m , p n,m,p n,m,p 的值,请你判断先手是否有必胜策略。
为了方便,我们用 f i f_i fi 来表示斐波那契数列的第 i i i 项,那么有 f 1 = 1 , f 2 = 2 f_1=1,f_2=2 f1=1,f2=2 , f i = f i − 1 + f i − 2 ( i ≥ 3 ) f_i=f_{i-1}+f_{i-2}(i \geq 3) fi=fi−1+fi−2(i≥3) 。
共有 T T T 组数据。
1 ≤ n , m , p ≤ 1 0 3 , 1 ≤ T ≤ 1 0 5 1 \leq n,m,p \leq 10^3,1 \leq T \leq 10^5 1≤n,m,p≤103,1≤T≤105
题目来源:HDU P1848(Fibonacci again and again)
//HDU 1848 -- Fibonacci again and again
#include
#include
int bj[1001],g[1001];
int f[101]={0,1,2};
void sg()
{
for(int i=1;i<=1000;i++)
{
memset(bj,0,sizeof(bj));
for(int j=1;j<=16;j++)
{
if(f[j]>i)
{
break;
}
bj[g[i-f[j]]]=1;
}
for(int j=0;j<=1000;j++)
{
if(bj[j]==0)
{
g[i]=j;
break;
}
}
}
}
int main()
{
for(int i=3;i<=16;i++)
{
f[i]=f[i-1]+f[i-2];
}
sg();
while(true)
{
int n=0,m=0,p=0;
scanf("%d %d %d",&n,&m,&p);
if(n==0 && m==0 && p==0)
{
break;
}
printf("%s\n",(g[n]^g[m]^g[p])!=0?"Fibo":"Nacci");
}
return 0;
}
有一堆共 n n n 个石子,每次取的个数要在 [ p , q ] [p,q] [p,q] 内,当式子个数不足 p p p 个时要一次将剩下的所有石子取完,取完最后一个石子的人输 ,问你先手是否有必胜策略。
1 ≤ n ≤ 2 16 , 1 ≤ p , q ≤ 2 16 1 \leq n \leq 2^{16},1 \leq p,q \leq 2^{16} 1≤n≤216,1≤p,q≤216 。
题目来源:HDU P2897(邂逅明下)
这是一道 打表找规律求SG值 :这类题目可以通过暴力求得小范围的SG值,再通过找规律得到SG值取值的规律来求解。
#include
#include
int bj[1001],g[1001];
int f[101]={0,1,2};
int len=0;
void sg()
{
for(int i=1;i<=1000;i++)
{
memset(bj,0,sizeof(bj));
if(i<f[1])
{
bj[g[0]]=1;
}
for(int j=1;j<=len;j++)
{
if(f[j]>i)
{
break;
}
bj[g[i-f[j]]]=1;
}
for(int j=0;j<=1000;j++)
{
if(bj[j]==0)
{
g[i]=j;
break;
}
}
}
}
int main()
{
int n=0,p=0,q=0;
scanf("%d %d %d",&n,&p,&q);
for(int i=p;i<=q;i++)
{
f[++len]=i;
}
sg();
for(int i=1;i<=n;i++)
{
printf("%d ",g[i]);
}
// if(g[n]!=0)
// {
// printf("LOST");
// }
// else
// {
// printf("WIN");
// }
return 0;
}
//HDOJ 2897 -- 邂逅明下
#include
#include
#include
using namespace std;
int main()
{
int n,q,p;
while ( scanf("%d%d%d",&n,&p,&q)!=EOF ) {
n%=(p+q);
if ( n>p || n==0 ) printf("WIN\n");
else printf("LOST\n");
}
return 0;
}
给 n n n 个点,然后给定这 n n n 个点的拓补图,有向无环。
然后给出你一个正整数 m m m ,表示图上有 m m m 个棋子,这 m m m 个棋子在哪几个点上。
现在有两个玩家来轮流移动这些棋子,谁先没办法移动所有的棋子谁输,问你先手是否有必胜策略。共有 T T T 组测试数据。
1 ≤ T ≤ 1 0 5 , 1 ≤ n ≤ 1000 , 1 ≤ m ≤ 10 1 \leq T \leq 10^5,1 \leq n \leq 1000,1 \leq m \leq 10 1≤T≤105,1≤n≤1000,1≤m≤10
题目来源:POJ P2425(A Chess Game)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int map[1010][1010];
int SG[1010];
int N;
int DFS(int n)
{
int i;
if(SG[n]!=-1) return SG[n];
bool used[1010];
memset(used,0,sizeof(used));
for(i=0; i<N; i++)
{
if(map[n][i] != -1)
used[DFS(i)]=true;
}
i=0;
while(used[i]) i++;
return SG[n]=i;
}
int main()
{
int i,j,k,t;
int X;
int tp,ans;
while(scanf("%d",&N) != EOF)
{
memset(map,255,sizeof(map));
memset(SG,255,sizeof(SG));
for(i=0; i<N; i++)
{
scanf("%d",&k);
if(k == 0)
{
SG[i] = 0;
}
for(j=0; j<k; j++)
{
scanf("%d",&t);
map[i][t] = 1;
}
}
while(scanf("%d",&X) != EOF)
{
if(X == 0) break;
ans = 0;
for(i=0; i<X; i++)
{
scanf("%d",&tp);
ans = ans ^DFS(tp);
}
if(ans != 0)
printf("WIN\n");
else
printf("LOSE\n");
}
}
return 0;
}
n n n 枚硬币排成一排,有的正面朝上,有的反面朝上。我们从左开始对硬币按 1 1 1 到 n n n 编号。
游戏者根据某些约束翻硬币,但他所翻动的硬币中,最右边那个硬币的必须是从正面翻到反面,谁不能翻谁就输,问你先手是否有必胜策略。
n n n 枚硬币排成一排,有的正面朝上,有的反面朝上。我们从左开始对硬币按 1 1 1 到 n n n 编号。游戏者所翻动的硬币必须是从正面翻到反面,谁不能翻谁就输。问你先手是否有必胜策略。
因为这题是只能翻一个硬币,那么这个硬币就是最右边的硬币,所以,每次操作是挑选一个正面的硬币翻成背面。
对于任意一个正面的硬币,SG值为1。
有 奇 数 个 正 面 硬 币 奇数个正面硬币 奇数个正面硬币 ,局面的 S G 值 = 1 SG值=1 SG值=1 ,先手 必 胜 必胜 必胜 ,有 偶 数 个 正 面 硬 币 偶数个正面硬币 偶数个正面硬币 ,局面的 S G 值 = 0 SG值=0 SG值=0 ,先手 必 败 必败 必败 。
约束条件 2 :每次能翻转一个或两个硬币(不用连续)
每个硬币的 S G 值 SG值 SG值 为它的编号,初始编号为 0 0 0 ,与 N I M 游 戏 NIM游戏 NIM游戏 是一样的。
如果对于一个局面,把 正 面 硬 币 的 S G 值 异 或 起 来 不 等 于 0 正面硬币的SG值异或起来不等于0 正面硬币的SG值异或起来不等于0 ,即 a 1 ⊕ a 2 ⊕ a 3 ⊕ … ⊕ a n = x a_1 ⊕ a_2 ⊕ a_3 ⊕ … ⊕ a_n = \text{x} a1⊕a2⊕a3⊕…⊕an=x ,对于 a n a_n an 来说一定有 a n ′ = a n ⊕ x < a n a_n' = a_n ⊕ \text{x} < a_n an′=an⊕x<an 。
如果 a n ′ = 0 a_n'=0 an′=0 ,意思就是说,把 a n a_n an 这个值从式子中去掉就可以了。对应游戏,就是把编号为 a n a_n an 的正面硬币翻成背面就可以了。因为 a n ⊕ x = 0 a_n ⊕ \text{x} =0 an⊕x=0,而 a 1 ⊕ a 2 ⊕ a 3 ⊕ … ⊕ a n = x a_1 ⊕ a_2 ⊕ a_3 ⊕ … ⊕ a_n=x a1⊕a2⊕a3⊕…⊕an=x ,即 a n ⊕ a 1 ⊕ a 2 ⊕ a 3 ⊕ … ⊕ a n = 0 a_n ⊕ a_1 ⊕ a_2 ⊕ a_3 ⊕ … ⊕ a_n=0 an⊕a1⊕a2⊕a3⊕…⊕an=0 ,即 a 1 ⊕ a 2 ⊕ a 3 ⊕ … ⊕ a n − 1 = 0 a_1 ⊕ a_2 ⊕ a_3 ⊕ … ⊕ a_{n-1} = 0 a1⊕a2⊕a3⊕…⊕an−1=0 ,只要在原来的 x \text{x} x 里面去掉 a n a_n an 就可以了。
如果 a n ′ ≠ 0 an' \not = 0 an′=0 ,意思就是说,把 a n a_n an 这个值从式子中去掉后再在式子中加上 a n ′ a_n' an′ , a n ′ < a n a_n' < a_n an′<an 。对应游戏,去掉 a n a_n an 就是把编号为 a n a_n an 的正面硬币翻成背面,加上 a n ′ a_n' an′ ,如果编号为 a n ′ a_n' an′ 的硬币是正面,我们就把它翻成背面,是背面就翻成正面,总之,就是翻转编号为 a n ′ a_n' an′ 的硬币。因为 a n ⊕ x ≠ 0 an ⊕ x \not= 0 an⊕x=0 ,所以 a n ⊕ a 1 ⊕ a 2 ⊕ a 3 ⊕ … ⊕ a n ≠ 0 a_n ⊕ a_1 ⊕ a_2 ⊕ a_3 ⊕ … ⊕ a_n \not= 0 an⊕a1⊕a2⊕a3⊕…⊕an=0 ,即 a 1 ⊕ a 2 ⊕ a 3 ⊕ … ⊕ a n − 1 ≠ 0 a_1 ⊕ a_2 ⊕ a_3 ⊕ … ⊕ a_{n-1} \not= 0 a1⊕a2⊕a3⊕…⊕an−1=0 ,而这里的 a n ′ = a 1 ⊕ a 2 ⊕ a 3 ⊕ … ⊕ a n − 1 a_n'=a_1 ⊕ a_2 ⊕ a_3 ⊕ … ⊕ a_{n-1} an′=a1⊕a2⊕a3⊕…⊕an−1 ,所以在 x x x 中去掉 a n a_n an 后,要对 a n ′ a_n' an′ 进行异或,也就是翻转,正转反,反转正。
约束条件 3 :每次必须连续翻转 k 个硬币
我们以 k = 3 k=3 k=3 为例。
我们计算的是个数为 n n n 的硬币中,其中最后一个硬币为正面朝上,的 s g 值 sg值 sg值 。
当 n = 1 n=1 n=1 时,硬币为:正,先手必输,所以 s g [ 1 ] = 0 sg[1]=0 sg[1]=0 。
当 n = 2 n=2 n=2 时,硬币为:反正,先手必输,所以 s g [ 2 ] = 0 sg[2]=0 sg[2]=0 。
当 n = 3 n=3 n=3 时,硬币为:反反正,先手必胜,所以 s g [ 3 ] = 1 sg[3]=1 sg[3]=1 。
当 n = 4 n=4 n=4 时,硬币为:反反反正,先手操作后为:反正正反,子状态局面的 S G = 0 ⊕ 1 = 1 SG=0 ⊕ 1=1 SG=0⊕1=1 ,那么 s g [ 4 ] = 0 sg[4]=0 sg[4]=0 。
当 n = 5 n=5 n=5 时,硬币为:反反反反正,先手操作后为:反反正正反,子状态局面的 S G = 1 ⊕ 0 = 1 SG=1 ⊕ 0 = 1 SG=1⊕0=1 ,那么 s g [ 5 ] = 0 sg[5] = 0 sg[5]=0 。
当 n = 6 n=6 n=6 时,硬币为:反反反反反正,先手操作后为:反反反正正反,子状态局面的 S G = 0 ⊕ 0 = 0 SG=0 ⊕ 0 = 0 SG=0⊕0=0 ,那么 s g [ 6 ] = 1 sg[6] = 1 sg[6]=1 。
…
然后我们得到了下面的这个表格:
n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | … |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
sg值 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | … |
由此我们可以知道,从编号为 1 1 1 开始, s g sg sg 值为: 001001001001...... 001 001 001 001...... 001001001001...... 。
通过继续观察,我们可以知道, s g sg sg 的形式为 000 … 01000 … 01 000…01000…01 000…01000…01 ,其中每一段 0 0 0 的个数都为 ( k − 1 ) (k-1) (k−1) 。
约束条件 4 :每次翻动一个硬币后,必须翻动其左侧最近三个硬币中的一个,即翻动第 x 个硬币后,必须选择 (x-1) 、 (x-2) 、 (x-3) 中的其中一个硬币进行翻动,除非 x 是小于等于 3 的 (Subtraction Games)
当 n = 1 n=1 n=1 时,硬币为:正,先手必赢,所以 s g [ 1 ] = 1 sg[1]=1 sg[1]=1 。
当 n = 2 n=2 n=2 时,硬币为:反正,先手必赢,因为先手可以翻成反反或正反,可能性为 2 2 2 ,所以 s g [ 2 ] = 2 sg[2]=2 sg[2]=2 。
…
然后我们得到了下面的这个表格:
n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | … |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
sg值 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | … |
这个与每次最多只能取 3 3 3 个石子的取石子游戏的 S G SG SG 分布一样,同样还有相似的这类游戏, 约 束 条 件 5 约束条件5 约束条件5 也是一样。
当 n = 1 n=1 n=1 时,硬币为:正,先手必输,所以 s g [ 0 ] = 0 sg[0]=0 sg[0]=0 。
当 n = 2 n=2 n=2 时,硬币为:反正,先手必赢,所以 s g [ 1 ] = 1 sg[1]=1 sg[1]=1 。
当 n = 3 n=3 n=3 时,硬币为:反反正,先手必赢,所以 s g [ 2 ] = 2 sg[2]=2 sg[2]=2 。
当 n = 4 n=4 n=4 时,硬币为:反反反正,先手必赢,所以 s g [ 3 ] = 3 sg[3]=3 sg[3]=3 。
当 n = 5 n=5 n=5 时,硬币为:反反反反正,先手必输,所以 s g [ 4 ] = 0 sg[4]=0 sg[4]=0 。
…
然后我们得到了下面的这个表格:
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | … |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
sg值 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | … |
初始编号从 0 0 0 开始。
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | … |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
sg值 | 1 | 2 | 4 | 7 | 8 | 11 | 13 | 14 | 16 | 19 | 21 | 22 | 25 | 26 | 28 | 31 | … |
看上去 s g 值 sg值 sg值 为 2 x 2 \text{x} 2x 或者 ( 2 x + 1 ) (2 \text{x} +1) (2x+1) 。我们称一个非负整数为 o d i o u s odious odious ,当且仅当该数的二进制形式的 1 1 1 出现的次数是奇数,否则称作 e v i l evil evil 。所以 1 1 1 , 2 2 2 , 4 4 4 , 7 7 7 是 o d i o u s odious odious 因为它们的二进制形式是 1 , 10 , 100 , 111 1,10,100,111 1,10,100,111 。而 0 , 3 , 5 , 6 0,3,5,6 0,3,5,6 是 e v i l evil evil ,因为它们的二进制形式是 0 , 11 , 101 , 110 0,11,101,110 0,11,101,110 。而上面那个表中,貌似 s g 值 sg值 sg值 都是 o d i o u s 数 odious数 odious数 。
所以当 2 x 2 \text{x} 2x 为 odious 时, sg值 是 2 x 2 \text{x} 2x,当 2 x 2 \text{x} 2x 是 evil 时, sg值 是 ( 2 x + 1 ) (2 \text{x} +1) (2x+1) 。
[1] 由感性认识到理性认识——透析一类搏弈游戏的解答过程。
[2] 组合游戏略述——浅谈SG游戏的若干拓展及变形。
[3] 博弈论。
[4] SG函数。
[5] hdu 1848Fibonacci again and again。
[6] 专题训练之博弈。
[7] 博弈by高嘉煊。
[8] sg函数入门题。
[9] 【转】博弈-翻硬币游戏。
[10] 博弈:关于SG函数的一些心得(知识总结+叙述证明+例题)。
[11] POJ2425(树形,无向无环图博弈)。