組合博弈游戲


 

² 組合博弈游戲的概念和特點

 

² 組合博弈游戲應滿足以下性質:

 

² 1. 有兩個游戲者。

 

² 2. 有一個可能的游戲狀態集。這個狀態集通常是有限的。

 

² 3. 游戲規則指定了在任何狀態下雙方的可能的走步和對應的后繼狀態集。如果在任意狀態下雙方的走步集合是相同的,那么說游戲是公平的(impartial) ,否則是不公平的(partizan) 。象棋是不公平的,因為每個人只能移動自己的子。

 

² 4. 兩個游戲者輪流走步。

 

² 5. 當到達一個沒有后繼狀態的狀態后,游戲結束。在普通游戲規則(normal playrule) 下,最后一個走步的游戲者勝;在misµere游戲規則下,最后一個走步的游戲者輸。如果游戲無限進行下去,我們認為雙方打平,但通常我們會附加規定:

 

² 6. 不管雙方怎么走步,游戲總能在有限步后結束。

 

² 其他規則包括:不允許隨機走步(不能扔色子或者隨機洗牌),且必須信息完全的(如隱藏走步是不允許的),有限步結束時不能產生平局。在本節中,我們只考慮公平游戲,並且通常只考慮普通游戲規則(最后走步的勝)。

 

² 和一般的雙人零和博弈不同的是,這里的博弈游戲是特殊的:它們很好的數學特性,使得我們能夠找到可判定輸贏的數學策略,而不需要進行狀態空間的搜索。

 

² P狀態和N狀態:假設雙方都采取最明智的策略,則對於一些狀態,剛完成走步的游戲者(Previous Player) 一定勝利,而對於其他狀態,下一個走步的游戲者(NextPlayer) 一定勝利。把兩種狀態稱為P狀態(P position) 和N狀態(N position) ,且有以下關系:

 

² 1. 所有終止狀態是P狀態

 

² 2. 能一步到達P狀態的狀態為N狀態

 

² 3. 每一步都將到達N狀態的狀態為P狀態

 

² 我們也可以把P狀態稱為必敗態,N狀態稱為必勝態,含義是直觀的。以上關系實際上給出了一個遞推計算所有狀態的P-N標號的算法。只要狀態集構成一個n個結點m條邊的有向無環圖(directed acyclic graph, DAG) ,則可以按照拓撲順序在O(m)時間內計算所有狀態的標號。可問題在於這樣的狀態往往有很多,能否通過數學方法直接判斷一個狀態是P狀態還是N狀態呢?

 

² 常見的組合博弈模型,有若干種,但也有很多情況,不能套用這些模型,要具體情況具體分析。

 

² 博弈樹模型

 

² 假設甲乙雙方在進行這種二人游戲,從唯一的一個初始局面開始,如果輪到甲方走棋,甲方有很多種着法,但只能選擇一個着法進行走棋。甲方走棋后,局面發生了變化,輪到乙方走棋,乙方也有很多種着法,但也只能選擇一個着法。從初始局面開始,甲乙兩方交替走棋,局面的變化可以表示成一個樹形結構,這就是博弈樹(game-tree)。一種井字棋的博弈樹,如圖所示。

 

² 每個局面可以用博弈樹的一個結點來表示,某方獲勝、失敗或雙方平局的結點構成了葉子結點。甲乙雙方在選擇着法時,不僅要考慮己方每一種着法的好壞,同時也要考慮對方會針對自己的每一種着法采取怎樣的着法來應對。顯然,博弈樹是一種特殊的與或樹,“或”結點和“與”結點是逐層交替出現的。己方擴展的結點之間是“或”關系,對方擴展的結點之間是“與”關系。

 

² Bash’s Game(巴什博弈)

 

² 所謂巴什博弈,是ACM題中最簡單的組合游戲,大致上是這樣的:

 

² 只有一堆n個物品,兩個人輪流從這堆物品中取物,規定每次至少取1個,最多取m個,最后取光者得勝。

 

² 顯然,如果n = m + 1,那么由於一次最多只能取m個,所以,無論先取者拿走多少個,后取者都能夠一次拿走剩余的物品,后者取勝。因此我們發現了如何取勝的法則:

 

² 如果 n = (m + 1) * r + s ,(r為任意自然數,s≤m),即n%(m+1) != 0,則先取者肯定獲勝。

 

² 巴什博弈還是很好理解的,以你是先手的角度考慮。你想把對手給弄垮,那么每一局,你都必須構建一個局勢,這個局勢就是每次都留給對手m+1的倍數個物品。因為,如果n=(m+1)r + s,(r為任意自然數,s≤m),那么先取者要拿走s個物品,如果后取者拿走k(≤m)個,那么先取者再拿走m+1-k個,結果剩下(m+1)(r-1)個,以后保持這樣的取法,那么先取者肯定獲勝。總之,要保持給對手留下(m+1)的倍數,就能最后獲勝。

 

² 這個游戲還可以有一種變相的玩法:兩個人輪流報數,每次至少報1個,最多報10個,誰能報到100者勝。

 

² 好運!該死的英語四級!

 

² Problem Description
大學英語四級考試就要來臨了, Kiki和Cici 在緊張的復習之余喜歡打牌放松。“升級”?“斗地主”?那多俗啊!作為計算機學院的學生,Kiki和Cici打牌的時候可沒忘記專業,她們打牌的規則是這樣的:
1、 總共n張牌;
2、 雙方輪流抓牌;
3、 每人每次抓牌的個數只能是2的冪次(即:1,2,4,8,16…)
4、 抓完牌,勝負結果也出來了:最后抓完牌的人為勝者;
假設Kiki和Cici都是足夠聰明並且每次都是Kiki先抓牌,請問誰能贏呢?

 

² Input
輸入數據包含多個測試用例,每個測試用例占一行,包含一個整數n(1<=n<=1000)。

 

Output
若Kiki能贏的話輸出“Kiki”,否則輸出“Cici”,每個實例的輸出占一行。

 

Sample Input
1
3

 

Sample Output
Kiki
Cici

 

² 如果你是先手,考慮你的必勝態。注意,因為任何正整數都能寫成若干個2的整數次方冪之和。由於規定只能取2的某個整數次方冪,只要你留給對手的牌數為3的倍數時,那么你就必贏,因為留下3的倍數時,對手有兩種情況:

 

² 1:如果輪到對方抓牌時只剩3張牌,對方要么取1張,要么取2張,剩下的你全取走,win!

 

² 2:如果輪到對方抓牌時還剩3*k張牌,對手不管取多少,剩下的牌數是3*x+1或者3*x+2。輪到你時,你又可以構造一個3的倍數。 所以無論哪種情況,當你留給對手為3*k的時候,你是必勝的。

 

² 題目說Kiki先抓牌,那么當牌數為3的倍數時,Kiki就輸了。否則Kiki就能利用先手優勢將留給對方的牌數變成3的倍數,就必勝。

 

² #include <iostream>
using namespace std;
int main ()
{
int N;
while ( cin >> N )
{
puts ( N % 3 != 0 ? “Kiki” : “Cici” );
}
return 0;
}

 

² 土地拍賣

 

² Problem Description

 

² 小雞同學和鵬程同學始終沒有逃過退學的命運,因為他們沒有在程序設計競賽中獲獎,還為了爭搶莎莎大打出手。現在等待他們的只能回家種田。要種田得有田才行,小雞聽說街上正在舉行一場拍賣會,拍賣的物品正好就是一塊田地。於是,小雞帶上他的全部積蓄,沖往拍賣會。后來發現,整個拍賣會只有小雞和他的死對頭鵬程。通過打聽,小雞知道這場拍賣的規則是這樣的:剛開始底價為0,兩個人輪流開始加價,不過每次加價的幅度要在1~N之間,當價格大於或等於田地的成本價M時,就把這塊田地賣給這次叫價的人。小雞和鵬程雖然比賽不行,但是對拍賣卻十分精通,而且他們兩個人都十分想得到這塊田地。所以他們每次都是選對自己最有利的方式進行加價。由於抽簽決定,所以每次都是由小雞先開始加價,請問,第一次加價的時候,小雞要出多少才能保證自己買得到這塊地呢?

 

² Input

 

² 本題目包含多組測試,請處理到文件結束(EOF)。每組測試占一行。每組測試包含兩個整數M和N(含義見題目描述,0<N,M<1100)

 

²

 

² Output

 

² 對於每組數據,在一行里按遞增的順序輸出小雞第一次可以加的價。兩個數據之間用空格隔開。如果小雞在第一次無論如何出價都無法買到這塊土地,就輸出”none”。

 

²

 

² Sample Input

 

² 4 2

 

² 3 2

 

² 3 5

 

²

 

² Sample Output

 

² 1

 

² None

 

² 3 4 5

 

² int main()
{
int n,m;
while(scanf(“%d%d”,&m,&n)!=EOF)
{
if(m%(n+1)==0)
{
printf(“none\n”);
continue;
}

 

²         if(m<=n)
{
printf(“%d”,m);
for(int i=m+1; i<=n; i++) printf(” %d”,i);
printf(“\n”);
continue;
}
printf(“%d\n”,m%(n+1));
}
return 0;
}

 

² 減法博弈

 

² 巴什博弈有一種變形,叫做減法博弈。用s表示一個正整數構成的集合,基於S所定義的減法游戲可以描述如下

 

² 有一個由n個石子組成的石子堆,兩名玩家輪流從中拿走石子,每次拿走石子的個數只能是集合S中的數。拿走最后一枚石子的玩家獲勝。

 

² 例:S = {1, 3, 4},如果在游戲的開始有100枚石子,那么哪個玩家獲勝?

 

  • 使用向后歸納的方法,可以計算出游戲的P位置和N位置如下:
  • 通過觀察發現,該游戲中的P位置(必敗態)是那些能被7整除或者模7余2的位置,其他位置都是N位置(必勝態)。用數學歸納法可以證明這個結論是正確的。
  • 事實上,如果k是P態(自己必敗),那么P+1、P+3、P+5能夠到達的位置,是N態(對方必敗),其他位置是P態。
  • 游戲的起始位置100是P位置,所以先手輸。

 

² Wythoff’s Game (威佐夫博弈)

 

² 所謂威佐夫博弈,是ACM題中常見的組合游戲中的一種,大致上是這樣的:

 

² 有兩堆石子,不妨先認為一堆有 10,另一堆有 15 個,雙方輪流取走一些石子,合法的取法有如下兩種:

 

² 1、在一堆石子中取走任意多顆;

 

² 2、在兩堆石子中取走相同多的任意顆;

 

² 約定取走最后一顆石子的人為贏家,求必勝策略。

 

² 兩堆石頭地位是一樣的,我們用余下的石子數(a,b)來表示狀態,並畫在平面直角坐標系上。

 

² 和前面類似,(0,0)肯定是 P 態,又叫必敗態。(0,k),(k,0),(k,k)系列的節點肯定不是 P 態,而是必勝態,你面對這樣的局面一定會勝,只要按照規則取一次就可以了。再看 y = x 上方未被划去的格點,(1,2)是 P 態。k > 2 時,(1,k)不是 P 態,比如你要是面對(1,3)的局面,你是有可能贏的。同理,(k,2),(1 + k, 2 + k)也不是 P 態,划去這些點以及它們的對稱點,然后再找出 y = x 上方剩余的點,你會發現(3,5)是一個 P 態,如此下去,如果我們只找出 a ≤ b 的 P 態,則它們是(0,0),(1,2),(3,5),(4,7),(6,10)……它們有什么規律嗎?

 

² 忽略(0,0),很快會發現對於第 i 個 P 態的 a,a = i * (sqrt(5) + 1)/2 然后取整;而 b = a + i。居然和黃金分割點扯上了關系。

 

² 前幾個必敗點如下:(0,0),(1,2),(3,5),(4,7),(6,10),(8,13)……可以發現,對於第k個必敗點(m(k),n(k))來說,m(k)是前面沒有出現過的最小自然數,n(k)=m(k)+k。

 

² 判斷一個點是不是必敗點的公式與黃金分割有關(我無法給出嚴格的數學證明,誰能給出嚴格的數學證明記得告訴我),為:

 

² m(k) = k * (1 + sqrt(5))/2

 

² n(k) = m(k) + k

 

² 一個必敗點有如下性質:

 

² 性質1:所有自然數都會出現在一個必敗點中,且僅會出現在一個必敗點中;

 

² 性質2:規則允許的任意操作可將必敗點移動到必勝點;

 

² 性質3:一定存在規則允許的某種操作可將必勝點移動到必敗點;

 

² 下面我們證明這3個性質。

 

² 性質1:所有自然數都會出現在一個必敗點中,且僅會出現在一個必敗點中;

 

² 證明:m(k)是前面沒有出現過的最小自然數,自然與前k-1個必敗點中的數字都不同;m(k)>m(k-1),否則違背m(k-1)的選擇原則;n(k)=m(k)+k>m(k-1)+(k-1)=n(k-1)>m(k-1),因此n(k)比以往出現的任何數都大,即也沒有出現過。又由於m(k)的選擇原則,所有自然數都會出現在某個必敗點中。性質1證畢。

 

² 性質2:規則允許的任意操作可將必敗點移動到必勝點;

 

² 證明:以必敗點(m(k),n(k))為例。若只改變兩個數中的一個,由於性質1,則得到的點一定是必勝點;若同時增加兩個數,由於不能改變兩數之差,又有n(k)-m(k)=k,故得到的點也一定是必勝點。性質2證畢。

 

² 性質3:一定存在規則允許的某種操作可將必勝點移動到必敗點;

 

² 證明:以某個必勝點(i,j)為例,其中j>i。因為所有自然數都會出現在某個必敗點中,故要么i等於m(k),要么j等於n(k)。

 

² 若i=m(k),j>n(k),可從j中取走j-n(k)個石子到達必敗點;

 

² 若i=m(k),j<n(k),可從兩堆同時拿走m(k)-m(j-m(k)),注意此時j-m(k) < n(k)-m(k) < k,從而到達必敗點( m(j-m(k)),m(j-m(k))+j-m(k));

 

² 若i>m(k),j=n(k),可從i中取走i-m(k)個石子到達必敗點;

 

² 若i<m(k),j=n(k),需要再分兩種情況,因為i一定也出現在某個必敗點中,若i=m(l),則從j中拿走j-n(l),若i=n(l),則從j中拿走j-m(l),從而到達必敗點(m(l),n(l))。

 

² 性質3證畢。

 

² 移動的皇后

 

² Problem Description

 

² 一個n * n棋盤上有一個皇后。每個人可以把它往左或下或左下45度移動任意多步。把皇后移動至左下角的游戲者獲勝。現在給出皇后初始的X坐標和Y坐標,如果輪到你先走,假設雙方都采取最好的策略,問最后你是勝者還是敗者。

 

² Input
輸入包含若干行,表示若干種皇后的初始情況,其中每一行包含兩個非負整數a和b,表示皇后的初始坐標,a和b都不大於1,000,000,000。

 

² Output
輸出對應也有若干行,每行包含一個數字1或0,如果最后你是勝者,則為1,反之,則為0。

 

² Sample Input

 

² 2 1
8 4
4 7

 

² Sample Output

 

² 0
1
0

 

² #include <iostream>

 

² using namespace std;

 

² int main()

 

² {

 

²     int m,n;

 

²     while(cin>>m>>n)

 

²     {
if (m > n) { int temp; temp = m; m = n; n =temp; }

 

²          int k = n – m;

 

²          int data = floor(k*(1.0+sqrt(5.0))/2.0);

 

²          if (data == m) cout<<0<<endl;

 

²     }

 

² }

 

² Ferguson博弈(清空/分割游戲)

 

² 清空/分割游戲也叫做Ferguson博弈。進行游戲需要用到兩個盒子。在游戲的開始,第一個盒子中有n枚石子,第二個盒子中有m個石子(n, m > 0)。參與游戲的兩名玩家輪流執行這樣的操作:清空一個盒子中的石子,然后從另一個盒子中拿若干石子到被清空的盒子中,使得最后兩個盒子都不空。當兩個盒子中都只有一枚石子時,游戲結束。最后成功執行操作的玩家獲勝。找出游戲中所有的P位置。

 

² 對於一個位置(x, y)來說,如果x, y中有一個偶數,那么(x, y)是N(必勝)位置。如果x和y都是奇數,那么(x, y)是P位置(必敗)。可以用數學歸納法證明。

 

² 證明(引自數學系唐思斯老師的證明):

 

² 證明結論:(x,y)至少一偶時,先手勝;都為奇時,先手敗

 

² 證明:

 

² (x,y)=(1,1)時是先手必敗態

 

² 下對max(x,y)>1進行歸納

 

² 1、當max(x,y)=2時,即(x,y)=(1,2)或(2,1)或(2,2),先手留下一個2分為(1,1),先手獲勝

 

² 即當max(x,y)=2時結論成立。

 

² 2、假設max(x,y)<k時結論都成立,現證max(x,y)=k時結論成立

 

² 若(x,y)中有一個偶數(設為a),先手將另一個清空,把偶數a分為兩個奇數b和c,由於b、c<a 小於等於 k,即max(b,c)<k,由假設,在(b,c)位置上后手作為新先手必敗,故先手勝

 

² 若(x,y)都為奇數,先手只能保留一個奇數並將其分解為一奇a一偶b,由於max(a,b)<max(x,y)=k,由假設,在(a,b)位置上后手作為新先手必勝,故先手敗

 

² Chomp! 博弈(巧克力游戲)

 

² 情人節的時候,潘典安買了一塊長方形的棋盤巧克力,和他最愛的女友一起吃,巧克力由n*m塊格子組成。為了增加情人節的情趣,潘典安和她女友輪流選擇一個格子,並把這個格子右面,上面和右上方的巧克力全部取走。取到左下角格子的玩家輸,就要給對方一個熱烈的吻。假設每次都是潘典安先手,他是否存在必勝策略呢?

 

² 下圖可以看作是一個3*8的巧克力被拿掉(6,2)和(3,2)兩塊后剩下的形狀:

 

² 答案是除了1*1的棋盤,對於其他大小的棋盤,先手總能贏。有一個很巧妙的證明可以保證先手存在必勝策略,可惜這個證明不是構造性的,也就是說沒有給出先手怎么下才能贏。證明如下:

 

² 如果后手能贏,也就是說后手有必勝策略,使得無論先手第一次取哪個石子,后手都能獲得最后的勝利。那么現在假設先手取最右上角的石子(n,m),接下來后手通過某種取法使得自己進入必勝的局面。但事實上,先手在第一次取的時候就可以和后手這次取的一樣,進入必勝局面了,與假設矛盾。

 

² Fibonacci’s Game (斐波那契博弈)

 

² 斐波那契博弈模型,是ACM題中常見的組合游戲中的一種,大致上是這樣的:

 

² 有一堆個數為 n 的石子,游戲雙方輪流取石子,滿足:

 

² 1. 先手不能在第一次把所有的石子取完;

 

² 2. 之后每次可以取的石子數介於 1 到對手剛取的石子數的 2 倍之間(包含 1 和對手剛取的石子數的 2 倍)。

 

² 約定取走最后一個石子的人為贏家,求必敗態。

 

² 這個和之前的威佐夫博弈和取石子游戲有一個很大的不同點,就是游戲規則的動態化。之前的規則中,每次可以取的石子的策略集合是基本固定的,但是這次有規則2:一方每次可以取的石子數依賴於對手剛才取的石子數。

 

² 這個游戲叫做Fibonacci Nim,肯定和Fibonacci數列f[n]:1,2,3,5,8,13,21,34,55,89,… 有密切的關系。如果試驗一番之后,可以猜測:先手勝當且僅當n不是Fibonacci數。換句話說,必敗態構成Fibonacci數列。

 

² 下面簡單談談“先手敗當且僅當n為Fibonacci數列”這一結論是怎么得來的。

 

² 這里要用到一個很有用的定理:任何正整數可以表示為若干個不連續的 Fibonacci 數之和。

 

² 這里定理涉及到數論,這里不做證明,想要知道證明過程的請找你們數學老師。下面只談如何把一個正整數表示為若干個不連續的 Fibonacci 數之和。

 

² 比如,我們要分解83,注意到83被夾在55和89之間,於是把83可以寫成83=55+28;然后再想辦法分解28,28被夾在21和34之間,於是28=21+7;依此類推 7=5+2,故83=55+21+5+2。

 

² 如果 n 是 Fibonacci 數,比如 n = 89。89前面的兩個Fibonacci 數是34和55。如果先手第一次取的石子不小於 34 顆,那么一定后手贏,因為 89 – 34 = 55 = 34 + 21 < 2*34,注意55是Fibonacci數。此時后手只要將剩下的全部取光即可,此時先手必敗。故只需要考慮先手第一次取得石子數 < 34 即可,於是剩下的石子數 x 介於 55 到 89 之間,它一定不是一個 Fibonacci 數。於是我們把 x 分解成 Fibonacci 數:x = 55 + f[i] + … + f[j],其中55 > f[i] > … > f[j],如果 f[j] ≤ 先手一開始所取石子數 y 的兩倍,那么對后手就是面臨 x 局面的先手,所以根據之前的分析,后手只要先取 f[j] 個即可,以后再按之前的分析就可保證必勝。

 

² 下證:f[j] ≤ 2y

 

² 反證法:假設f[j]>2y,則 y < f[j]/2 = (f[j-1] + f[j-2])/2 < f[j-1]。而最初的石子數是個斐波那契數,即 n = f[k] = x + y < f[k-1] + f[i] + … + f[j] + f[j-1] ≤ f[k-1]+f[i]+f[i-1] ≤ f[k-1]+f[k-2] ≤ f[k] (注意第一個不等號是嚴格的),矛盾!f[j] ≤ 2y得證。

 

² 如果 n 不是 Fibonacci 數,比如n=83,我們看看這個分解有什么指導意義:假如先手取2顆,那么后手無法取5顆或更多,而5是一個Fibonacci數,如果猜測正確的話,(面臨這5顆的先手實際上是整個游戲的后手)那么一定是整個游戲的先手取走這5顆石子中的最后一顆,而這個我們可以通過第二類歸納法來繞過,同樣的道理,根據“先手敗當且僅當n為Fibonacci數列”,接下去先手取走接下來的后21顆中的最后一顆,再取走后55顆中的最后一顆,那么先手贏。

 

² 尼姆博弈(Nimm’s Game)

 

² 尼姆博弈模型,是ACM題中常見的組合游戲中的一種,大致上是這樣的:

 

² 有3堆各若干個物品,兩個人輪流從某一堆取任意多的物品,規定每次至少取1個,多者不限,最后取光者得勝。

 

² 這種情況最有意思,它與二進制有密切關系,我們用(a,b,c)表示某種局勢,首先(0,0,0)顯然是必敗態,無論誰面對(0,0,0) ,都必然失敗;第二種必敗態是(0,n,n),自己在某一堆拿走k(k ≤ n)個物品,不論k為多少,對方只要在另一堆拿走k個物品,最后自己都將面臨(0,0,0)的局勢,必敗。仔細分析一下,(1,2,3)也是必敗態,無論自己如何拿,接下來對手都可以把局勢變為(0,n,n)的情形。

 

² 計算機算法里面有一種叫做按位模2加,叫做異或的運算,我們用符號XOR表示這種運算,這種運算和一般加法不同的一點是1 XOR 1 = 0。先看(1,2,3)的按位模2加的結果:

 

² 1 = 二進制01

 

² 2 = 二進制10

 

² 3 = 二進制11  XOR

 

² ———————

 

² 0 = 二進制00 (注意不進位)

 

²

 

² 對於奇異局勢(0,n,n)也一樣,結果也是0。

 

² 任何奇異局勢(a,b,c)都有a XOR b XOR c = 0。

 

² 如果我們面對的是一個非必敗態(a,b,c),要如何變為必敗態呢?假設 a < b < c,我們只要將 c 變為a XOR b,即可。因為有如下的運算結果:

 

² a XOR b XOR (a XOR b)=(a XOR a) XOR (b XOR b) = 0 XOR 0 = 0。

 

² 要將c 變為a XOR b,只要對 c進行 c-(a XOR b)這樣的運算即可。

 

² 尼姆博弈模型可以推廣到:有n堆若干個物品,兩個人輪流從某一堆取任意多的物品,規定每次至少取一個,多者不限,最后取光者得勝。

 

² 這個游戲中的變量是堆數k和各堆的物品數N1,N2,……,Nk。對應的組合問題是,確定先手獲勝還是后手獲勝以及兩個游戲人應該如何取物品才能保證自己獲勝(獲勝策略)。

 

² 為了進一步理解Nim取物品游戲,我們考查某些特殊情況。如果游戲開始時只有一堆物品,先手則通過取走所有的物品而獲勝。現在設有2堆物品,且物品數量分別為N1和N2。游戲者取得勝利並不在於N1和N2的值具體是多少,而是取決於它們是否相等。設N1!=N2,先手從大堆中取走的物品使得兩堆物品數量相等,后手再拿,於是,先手以后每次取子的數量與后手相等而最終獲勝。但是如果N1= N2,則:后手只要按着先手拿的數量在另一堆中取相等數量的物品,最終獲勝者將會是后手。這樣,兩堆的取子獲勝策略就已經找到了。

 

² 現在我們如何從兩堆的取子策略擴展到任意堆數中呢?

 

² 首先來回憶一下,每個正整數都有對應的一個二進制數,例如:57(10) = 111001(2) ,即:57(10)=25+24+23+20。於是,我們可以認為每一堆物品數由2的冪數的子堆組成。這樣,含有57枚物品大堆就能看成是分別由數量為25、24、23、20的各個子堆組成。

 

² 現在考慮各大堆大小分別為N1,N2,……Nk的一般的Nim博弈。將每一個數Ni表示為其二進制數(數的位數相等,不等時在前面補0):

 

² N= as…a1a0

 

² N= bs…b1b0

 

² ……

 

² N= ms…m1m0

 

² 如果每一種大小的子堆的個數都是偶數,我們就稱Nim博弈是平衡的,而對應位相加是偶數的稱為平衡位,否則稱為非平衡位。因此,Nim博弈是平衡的,當且僅當:

 

² a+bs + … + ms 是偶數,即aXOR bs XOR … XOR ms  = 0

 

² ……

 

² a+b+ … + m是偶數,即aXOR b1 XOR … XOR m1 = 0

 

² a+b0 + … + m0是偶數,即aXOR b0 XOR … XOR m0 = 0

 

² 於是,我們就能得出尼姆博弈中先手獲勝策略:

 

² Bouton定理:先手能夠在非平衡尼姆博弈中取勝,而后手能夠在平衡的尼姆博弈中取勝。即,狀態(x1, x2, x3, …, xn)為P狀態當且僅當x1 xor x2 xor x3 xor … xor xn=0。這樣的操作也稱為Nim和(Nim Sum) 。

 

² 我們以一個兩堆物品的尼姆博弈作為試驗。設游戲開始時游戲處於非平衡狀態。這樣,先手就能通過一種取子方式使得他取子后留給后手的是一個平衡狀態下的游戲,接着無論后手如何取子,再留給先手的一定是一個非平衡狀態游戲,如此反復進行,當后手在最后一次平衡狀態下取子后,先手便能一次性取走所有的物品而獲勝。而如果游戲開始時游戲牌平衡狀態,那根據上述方式取子,最終后手能獲勝。

 

² 下面應用此獲勝策略來考慮4堆的Nim博弈。其中各堆的大小分別為7,9,12,15枚硬幣。用二進制表示各數分別為:0111,1001,1100和1111。於是可得到如下一表:

 

²

 

² 由Nim博弈的平衡條件可知,此游戲是一個非平衡狀態的Nim博弈,因此,先手在按獲勝策略一定能夠取得最終的勝利。具體做法有多種,先手可以從大小為12的堆中取走11枚硬幣,使得游戲達到平衡(如下表),

 

² 之后,無論后手如何取子,先手在取子后仍使得游戲達到平衡。

 

² 同樣的道理,先手也可以選擇大小為9的堆並取走5枚硬幣而剩下4枚,或者,先手從大小為15的堆中取走13枚而留下2枚。

 

² 歸根結底, Nim博弈的關鍵在於游戲開始時游戲處於何種狀態(平衡或非平衡)和先手是否能夠按照取子游戲的獲勝策略來進行游戲。

 

² 當堆數大於2時,我們看出Bouton定理依舊適用,但還沒給出嚴格的證明,下面用數學歸納法證明。

 

² 證明:如果每堆都為0,顯然是P狀態(必敗)。下面驗證P狀態和N狀態的后兩個遞推關系:

 

² 一、每個N狀態都可以一步到達P狀態。

 

² 證明是構造性的。檢查Nim和X的二進制表示中最左邊一個1,則隨便挑一個該位為1的物品堆Y,根據Nim和進行調整(0變1,1變0)即可。例如Nim和為100101011,而其中有一堆為101110001。為了讓Nim和變為0,只需要讓操作的物品數取操作前的物品數和Nim的異或即可。

 

² 顯然操作后物品數變小,因此和合法的。設操作前其他堆的Nim和為Z,則有Y xor Z = X。操作后的Nim和為X xor Y xor Z = X xor X = 0,是一個P狀態。

 

² 二、每個P狀態(必勝態)都不可以一步到達P狀態

 

² 由於只能改變一堆的物品,不管修改它的哪一位,Nim的對應位一定不為0,不可能是P狀態。

 

² 這樣就證明了Bouton定理。

 

² Nim博弈中如果規定最后取光者輸,情況是怎樣的?初看起來問題要復雜很多(因為不能主動拿了,而要“躲着”拿,以免拿到最后一個物品),事實上確實有很多游戲規則比普通規則要困難很多,但對於Nim游戲來說,幾乎是一樣的:

 

² 首先按照普通規則一樣的策略進行,直到恰好有一個物品數大於1的堆x。在這樣的情況下,只需要把堆x中的物品拿得只剩1個物品或者拿完,讓對手面臨奇數堆物品,這奇數堆物品每堆恰好1個物品。這樣的狀態顯然是必敗的。由於你每次操作后需要保證Nim和為0,因此不可能在你操作后首次出現“恰好有一個物品數大於1的堆”。新游戲得到了完美解決。

 

² SG函數與SG定理

 

² 現在我們來研究一個看上去似乎更為一般的游戲:給定一個有向無環圖和一個起始頂點上的一枚棋子,兩名選手交替的將這枚棋子沿有向邊進行移動,無法移動者判負。事實上,這個游戲可以認為是所有Impartial Combinatorial Games的抽象模型。也就是說,任何一個ICG都可以通過把每個局面看成一個頂點,對每個局面和它的子局面連一條有向邊來抽象成這個“有向圖游戲”。下面我們就在有向無環圖的頂點上定義Sprague-Garundy函數,簡稱SG函數。

 

² 首先定義mex(minimal excludant)運算,這是施加於一個集合的運算,表示最小的不屬於這個集合的非負整數。例如集合N={0,1,2,3,4,5,6},則mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。

 

² Sprague-Grundy 函數是定義在組合游戲狀態上的函數,用g (X)表示X狀態的g函數值。它的定義如下:

 

² g(x)=mex{ g(y) | y是x的后繼 }。

 

² 或者表示為:

 

² g (X)= min{n| n∈N, n>=0,n≠ for y, y是x的后繼}

 

² 形象的說就是X的g函數值為X的后繼點的SG值中沒有出現過的最小值。

 

² SG函數的性質:

 

² 1、所有的終點(先手必敗態),也就是沒有出邊的頂點,其SG值為0,因為它的后繼集合是空集;

 

² 2、對於一個g(x)=0的頂點x,它的所有后繼y都滿足g(y)!=0;

 

² 3、對於一個g(x)!=0的頂點,必定存在一個后繼y滿足g(y)=0。

 

² 下面將引入Sprague-Grundy定理,簡稱SG定理,並給上述的SG函數的性質進行證明。

 

² 通過下面的定理可以建立SG函數與N局面和P局面的關系:

 

² 引理:對於任意的局面x,若g(x)=0則x是P局面(必敗態),否則x是N局面(必勝態)。

 

² 證明:我們對局面作數學歸納法:

 

² 1. 對於最終局面x,由定義x是P局面(必敗態),而此時g(x)=0, 引理成立。

 

² 2. 假設局面x的所有后繼局面都滿足引理。

 

³ 若x的后繼局面中存在P局面(必敗態)y,則x是N局面(必勝態),同時g(y)=0,故g(x)不等於0;

 

³ 若x的后繼局面y中不存在P局面,則顯然x是P局面;同時由於不存在g(y)=0,故g(x)=0。

 

² 由歸納假設,引理對於所有局面x成立。

 

² 我們通過計算有向無環圖的每個頂點的SG值,就可以對每種局面找到必勝策略了。

 

² 實際中,SG函數的用途遠沒有這樣簡單。如果將有向圖游戲變復雜一點,比如說,有向圖上並不是只有一枚棋子,而是有n枚棋子,每次可以任選一顆進行移動,這時,怎樣找到必勝策略呢?

 

² 再來考慮一下頂點的SG值的意義。當g(x)=k時,表明對於任意一個0 ≤ i<k,都存在x的一個后繼y滿足g(y)=i。也就是說,當某枚棋子的SG值是k時,我們可以把它變成0、變成1、……、變成k-1,但絕對不能保持k不變。不知道你能不能根據這個聯想到Nim游戲,Nim游戲的規則就是:每次選擇一堆數量為k的石子,可以把它變成0、變成1、……、變成k-1,但絕對不能保持k不變。這表明,如果將n枚棋子所在的頂點的SG值看作n堆相應數量的石子,那么這個Nim游戲的每個必勝策略都對應於原來這n枚棋子的必勝策略!

 

² 也就是說:游戲者可以通過一步走棋把圖的當前狀態值任意的減小(當然必須保證狀態值始終>=0)。

 

² 如果游戲者處在一個點x,g(x)=0。那么游戲者無論如何移動,下一個點的SG值都不等於0

 

² 對於n個棋子,設它們對應的頂點的SG值分別為(a1,a2,…,an),再設局面(a1,a2,…,an)時的Nim游戲的一種必勝策略是把某個ai變成k,那么原游戲的一種必勝策略就是把第i枚棋子移動到一個SG值為k的頂點。這聽上去有點過於神奇——怎么繞了一圈又回到Nim游戲上了。

 

² 可以用如下方式定義組合游戲的和:初始局面包含每個子游戲的初始局面,而每次每個游戲者可以任意選一個游戲,進行一次合法走步,而讓其他游戲局面保持不變。

 

² 3堆火柴的Nim游戲可以作看是3個一堆火柴的Nim游戲之和。一堆Nim游戲是簡單的:直接把所有火柴拿掉即可;但3堆火柴卻復雜得多。看樣子,即使每個游戲都很簡單,它們的和也可能很復雜。

 

² 雖然看起來很復雜,但Sprague-Grundy定理提供了一個很好的方案解決這一問題:

 

² Sprague-Grundy定理:游戲和的SG函數等於各子游戲SG函數的Nim和,即:設gi(x)為Gi的SG函數(1 ≤ i ≤ n),則G = G1+ G2+ … + Gn的SG函數g( x1, x2, …, x) = g1(x1)⊕ g2(x2) ⊕ … ⊕ gn(xn)(其中⊕為異或運算)。

 

² 證明:對於G的任意局面x ( x1, x2, …, x},設b = g1(x1)⊕ g2(x2) ⊕ … ⊕ gn(xn) ,對於任意一個非負整數a<b,如果我們能證明下面兩個事實:

 

² (1)都存在x的一個后繼局面y,使得g(y)=a;

 

² (2)不存在x的后繼局面y,使得g(y)=b;

 

² 則b就是滿足要求的x的SG函數值,命題也就隨之得證。

 

² 對於事實1,令d=a⊕b,設k是d的二進制位的最高位,即2k-1 ≤ d < 2k。 由於a<b,故a的第k位為0,b的第k位為1。故g1(x1)、 g2(x2) 、… 、gn(xn)中至少有一個二進制位第k位為1,不妨設為g1(x1),那么有d⊕g1(x1)< g1(x1),根據SG函數g1的定義,必存在x1的一個后繼局面y1,使得g1(y1)=d⊕g1(x1)。

 

² 故存在{x1,x2,…,xn}的一個后繼局面{y1,x2,x3,…,xn},它的SG函數值為:

 

² g(y1,x2,x3,…,xn)=g1(y1)⊕g2(x2)⊕…⊕gn(xn)

 

²                           = d⊕g1(x1)⊕g2(x2)⊕…⊕gn(xn) = d⊕b

 

²                           = a⊕b⊕b = a

 

² 至此事實1成立

 

² 對於事實2,反設若存在這樣的后繼局面y,不妨設y={y1,x2,…,xn}(y1是x1的后繼局面),   則有:

 

² g1(x1)⊕g2(x2)⊕…⊕gn(xn) = g1(y1)⊕g2(x2)⊕…⊕gn(xn)

 

² 即:g1(x1)=g1(y1),這與SG函數g1的性質矛盾。因此事實2成立。

 

² 由Sprague-Grundy定理可知,對於復雜的公平組合博弈,如果我們可以將它們分解成若干個子游戲的聯合,就可以通過求解子游戲的SG函數,方便地求得原游戲的SG函數,從而快速判斷勝負情況。

 

² 有了上面的公平組合博弈的理論為基礎,我們就可以來解決引言中提出的問題了。

 

² 保齡球游戲

 

² 在一行中有n個木瓶,你和你的朋友輪流用保齡球去打這些木瓶,由於你們都是高手,每一次都可以准確的擊倒一個或相鄰的兩個木瓶,誰擊倒最后一個剩余的木瓶誰將獲得勝利。如果由你先打,請你分析,你應該采取什么策略來確保贏得勝利?

 

² 分析:為了看清楚問題的本質,用另一種方式來描述這個游戲。最開始有一堆石子(n個),每一次你可以進行以下四種操作中的一種:

 

² 1. 從中取出一顆石子;

 

² 2. 從中取出兩顆石子;

 

² 3. 從一堆中取出一顆石子,並且將這一堆中余下的石子任意分成兩堆(每堆至少一顆);

 

² 4. 從一堆中取出兩顆石子,並且將這一堆中余下的石子任意分成兩堆(每堆至少一顆)。

 

² 這四種操作,實際上就依次對應於原來游戲中的以下四種擊倒法:

 

² 1. 擊倒一段連續的木瓶中最靠邊的一個;

 

² 2. 擊倒一段連續的木瓶中最靠邊的連續兩個;

 

² 3. 擊倒一段連續的木瓶中不靠邊的一個;

 

² 4. 擊倒一段連續的木瓶中不靠邊的連續兩個。

 

² 把局面看作頂點,游戲規則看作邊,這是一個典型的圖游戲。

 

² 如果當前局面被分成了M堆,(A1,A2,…,Am),則SG(A1,A2,…,Am) = SG(A1)⊕SG(A2)⊕…⊕SG(Am)。對某一堆來說:

 

² 顯然,SG(0)=0。

 

² 剩余1個時,只能取到0個,而SG(0)=0,所以SG(1)=1。

 

² 剩余2個時,可以取到0或1,其中SG(0)=0,SG(1)=1,所以SG(2)=2。

 

² 剩余3個時,我們可以把局面變成1或2或兩堆均為1。

 

² 其中SG(1)=1,SG(2)=2,SG(1, 1)=SG(1) ⊕ SG(1)=0,所以SG(3)=3。

 

² SG(4)可分解為{SG(2), SG(3),SG(2)⊕SG(1), SG(1)⊕SG(1)} ={2,3,3,0},所以SG(4)=1。

 

² 對於任意一種局面P,的SG值為SG(P),為了贏得勝利,我們只需將他的局面變成Q,使得SG(Q)=0即可。

 

² 對於每一個N值,我們為了求出他的SG值,時間復雜度為O(N) ,如果只要求你求出你第一步應該如何行動,那么這種普通的方法需要O(N2)的復雜度,顯然不能令我們滿意。

 

² 這個問題看似已經解決,但我們可以進行優化。事實上,我們通過觀察較小的數的SG值,可以發現:

 

²  0 ~11的SG值為:0 1 2 3 1 4 3 2 1 4 2 6

 

² 12~23的SG值為:4 1 2 7 1 4 3 2 1 4 6 7

 

² 24~35的SG值為:4 1 2 8 5 4 7 2 1 8 6 7

 

² 36~47的SG值為:4 1 2 3 1 4 7 2 1 8 2 7

 

² 48~59的SG值為:4 1 2 8 1 4 7 2 1 4 2 7

 

² 60~71的SG值為:4 1 2 8 1 4 7 2 1 8 6 7

 

² 72~83的SG值為:4 1 2 8 1 4 7 2 1 8 2 7

 

² 並且從72開始,SG值以12為循環節,不斷的重復出現,這樣我們求出所有SG值的復雜度就降到了常數,這樣判斷第一步的如何選擇的復雜度就降為了O(N)。

 

² 具體問題具體分析

 

² 也有很多題目不能完全照搬上述模型的,這就需要具體問題具體分析。來看2011年湖南省程序設計競賽的題目E:

 

² 盒子游戲

 

² 題目大意:

 

² 有兩個相同的盒子,其中一個裝了n個球,另一個裝了一個球。Alice和Bob發明了一個游戲,規則如下:Alice和Bob輪流操作,Alice先操作。每次操作時,游戲者先看看哪個盒子里的球的數目比較少,然后清空這個盒子(盒子里的球直接扔掉),然后把另一個盒子里的球拿一些到這個盒子中,使得兩個盒子都至少有一個球。如果一個游戲者無法進行操作,他(她)就輸了。

 

² 面對兩個各裝一個球的盒子,Bob無法繼續操作,因此Alice獲勝。你的任務是找出誰會獲勝。假定兩人都很聰明,總是采取最優策略。

 

² 輸入

 

² 輸入最多包含300組測試數據。每組數據僅一行,包含一個整數n(2 ≤ n ≤ 109)。輸入結束標志為n=0

 

² 輸出

 

² 對於每組數據,輸出勝者的名字。

 

² 樣例輸入

 

² 2

 

² 3

 

² 4

 

² 0

 

² 樣例輸出

 

² Alice

 

² Bob

 

² Alice

 

² 分析:

 

² 這個題目,無法套用巴什博弈、威佐夫博弈、斐波那契博弈、尼姆博弈這四個常見模型,和清空/分割游戲也有差別。如果用萬能的alpha-beta剪枝算法絕對超時。怎么辦?不妨耐心的仔細分析,找出規律,因為競賽題都是應試教育下的變態產物(不過也能培養一頂的能力),你要做出這類題,第一是要有耐心,第二是你的思維要比出題的劉汝佳之流更加變態才行。

 

² 仔細分析,可以發現,既然球數量少的盒子里的球都是要丟棄的,這道題可以轉換為,在一個剩下n個球的盒子里,拿走k個球,其中1 ≤ k ≤ int(n/2),還剩下int(n – k)個球。如果某個游戲者面對盒子里的球只剩下1個,即n=1時,就敗了。引入函數win(n),表示這個盒子剩下的球數為n時,當前游戲者是否能獲得必勝態,由於不存在平局,當win(n)=1時,當前游戲者能獲得必勝態,當win(n)=0時由於對手足夠聰明,當前游戲者只能獲得必敗態。所以:

 

² n=1時,根據游戲規則,對當前游戲者來說是必敗態,即win(1) = 0。

 

² n>1時,對當前游戲者拿走k個球,還剩下r個球留給對方,r = n – k,其中1 ≤ k ≤ (int)(n/2),這樣,r就有個范圍,即int((n + 1)/2) ≤ r ≤ n – 1。博弈樹是一種特殊的與或樹,“或”結點和“與”結點是逐層交替出現的。己方擴展的結點之間是“或”關系,對方擴展的結點之間是“與”關系(關於博弈樹的這段話關緊要,看不懂的同學可以掠過,看得懂的同學能在瞬間明白是怎么回事)。所以只要win(int((n + 1)/2))、win(int((n + 1)/2) + 1)、win(int((n + 1)/2) + 2)、…、win(n – 1)中所有的值是1,那么對方都必勝,自己就只能獲得必敗態;但是,只要win(int((n + 1)/2))、win(int((n + 1)/2) + 1)、win(int((n + 1)/2) + 2)、…、win(n – 1)中存在某個值是0,那么自己可以獲得必勝態。

 

² 換句話來說:

 

² 一旦發現某個r值使得win(r) = 0,則從win(r + 1)到win(2 * r)的值都是1;

 

² 一旦發現win(r + 1)到win(2 * r)的值都是1,則win(2 * r + 1) = 0;

 

² ……

 

² 上述分析很重要,搞明白上述分析后,

 

² r = 1時,已知win(1) = 0,能推出win(2) = 1,以及win(3) = 0。

 

² r = 3時,由win(3) = 0,又能推出win(4) = win(5) = win(6) = 1,以及win(7) = 0。

 

² r = 7時,由win(7) = 0,又能推出win(8) = win(9) = … = win(14) = 1,以及win(15) = 0。

 

² r = 15時,由於win(15) = 0,又能推出win(16) = win(17) = … = win(30) = 1,以及win(31) = 0。

 

² r = 31時,由於win(31) = 0,又能推出win(32) = win(33) = … = win(62) = 1,以及win(63) = 0。

 

² ……

 

² 自此,由數學歸納法可以證明,只有n = (int)pow(2, m) – 1時(m為非負整數),win(n) = 0,當前游戲者面臨必敗態,除此之外,當前選手都能面臨必勝態!

 

² 求win函數的代碼我寫了一個,只有寥寥數行。

 

² 農大公布的標准程序采用的是遞歸的方法,我個人認為沒有我上面的算法效率高,我的算法實質上就是判斷n+1是不是構成2的某個非負整數次方冪。

 

² 豬縣長同學寫的程序可能效率更高,他采用的是預制表的辦法,將問題規模內的2的所有整數次方冪-1的值放在一個向量或者數組中,然后用類似二分查找的辦法去找,找到了就是先手必勝,否則先手必敗。

 

² #include <iostream>

 

² using namespace std;

 

² int Win(int n)

 

² {

 

²     int m = log(n + 1) / log(2);

 

²     int k = pow(2, m);

 

²     if(k == n + 1) return 0; //先手必敗

 

²     return 1; //先手必勝

 

² }

 

² int main()

 

² {

 

²     int n;

 

²     cin >> n;

 

²     while( n > 0)

 

²     {

 

²         if(Win(n)) cout << “Alice\n”;

 

²         else cout << “Bob\n”;

 

²         cin >> n;

 

²     }

 

²     return 0;

 

² }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM