尼姆博弈。
講解:有三堆各若干個物品,兩個人輪流從某一堆取任意多的物品,規定每次至少取乙個,多者不限,最後取光者得勝。
這種情況最有意思,它與二進位制有密切關係,我們用(a,b,c)表示某種局勢,首先(0,0,0)顯然是奇異局勢,無論誰面對奇異局勢,都必然失敗。第二種奇異局勢是(0,n,n),只要與對手拿走一樣多的物品,最後都將導致(0,0,0)。仔細分析一下,(1,2,3)也是奇異局勢,無論對手如何拿,接下來都可以變為(0,n,n)的情形。
計算機演算法裡面有一種叫做按位模2加,也叫做異或的運算,我們用符號(+)表示這種運算。這種運算和一般加法不同的一點是1+1=0。先看(1,2,3)的按位模2加的結果:
1 =二進位制01
2 =二進位制10
3 =二進位制11 (+)
———————
0 =二進位制00 (注意不進製)
對於奇異局勢(0,n,n)也一樣,結果也是0。
任何奇異局勢(a,b,c)都有a(+)b(+)c =0。
如果後手面對的是乙個非奇異局勢(a,b,c),要如何變為奇異局勢呢?假設 a (+)b< c,我們只要將 c 變為 a(+)b,即可,因為有如下的運算結果: a(+)b(+)(a(+)b)=(a(+)a)(+)(b(+)b)=0(+)0=0。要將c 變為a(+)b,只要從 c中減去
c-(a(+)b)即可。 這樣若先手面對乙個奇異局勢,無論如何去取,必然會從乙個異或值為0(奇異局勢)轉移到乙個異或值不為0(非奇異局勢),直到最後變成1(+)1==0的時候,先手只能取走乙個1,而後手取走剩下的1就勝利了。
舉個例子:
甲:(7,8,9)->(1,8,9)奇異局勢
乙:(1,8,9)->(1,8,4)
甲:(1,8,4)->(1,5,4)奇異局勢
乙:(1,5,4)->(1,4,4)
甲:(1,4,4)->(0,4,4)奇異局勢
乙:(0,4,4)->(0,4,2)
甲:(0.4,2)->(0,2,2)奇異局勢
乙:(0,2,2)->(0,2,1)
甲:(0,2,1)->(0,1,1)奇異局勢
乙:(0,1,1)->(0,1,0)
甲:(0,1,0)->(0,0,0)奇異局勢
甲勝。取火柴遊戲:
問題1:今有若干堆火柴,兩人依次從中拿取,規定每次只能從一堆中取若干根, 可將一堆全取走,但不可不取,最後取完者為勝,求必勝的方法。 (sg遊戲)
問題2:今有若干堆火柴,兩人依次從中拿取,規定每次只能從一堆中取若干根, 可將一堆全取走,但不可不取,最後取完者為負,求必勝的方法。(anti-sg遊戲)
第乙個問題:
定義:若所有火柴數異或為0,則該狀態被稱為利他態,用字母t表示;否則,為利己態,用s表示。
[定理1]:對於任何乙個s態,總能從一堆火柴中取出若干個使之成為t態。
證明:若有n堆火柴,每堆火柴有a(i)根火柴數,那麼既然現在處於s態,
c = a(1) xor a(2) xor … xor a(n) > 0;
把c表示成二進位制,記它的二進位制數的最高位為第p位,則必然存在乙個a(t),它二進位制的第p位也是1。(否則,若所有的a(i)的第p位都是0,這與c的第p位就也為0矛盾)。
那麼我們把x = a(t) xor c,則得到x < a(t).這是因為既然a(t)的第p位與c的第p位同為1,那麼x的第p位變為0,而高於p的位並沒有改變。所以x < a(t).而
a(1) xor a(2) xor … xor x xor … xor a(n)
= a(1) xor a(2) xor … xor a(t) xor c xor … xor a(n)
= a(1) xor a(2) xor… xor a(n) xor a(1) xor a(2) xor … xora(n)
= 0這就是說從a(t)堆中取出 a(t) – x 根火柴後狀態就會從s態變為t態。證畢
[定理2]:t態,取任何一堆的若干根,都將成為s態。
證明:用反證法。
若c = a(1) xor a(2) xor … xor a(i) xor … xor a(n) = 0;
c』 = a(1) xor a(2) xor … xor a(i』) xor c xor … xor a(n) = 0;
則有c xor c』 = a(1) xor a(2) xor … xor a(i) xor … xor a(n) xor a(1) xor a(2) xor … xor a(i』) xor c xor … xor a(n) = a(i) xor a(i』) =0
進而推出a(i) = a(i』),這與已知矛盾。所以命題得證。
[定理 3]:s態,只要方法正確,必贏。
最終勝利即由s態轉變為t態,任何乙個s態,只要把它變為t態,(由定理1,可以把它變成t態。)對方只能把t態轉變為s態(定理2)。這樣,所有s態向t態的轉變都可以有己方控制,對方只能被動地實現由t態轉變為s態。故s態必贏。
[定理4]:t態,只要對方法正確,必敗。
由定理3易得。
以上可以得到,對於sg遊戲,若初始局面的異或值為0,那麼先手必敗,否則先手必勝。
第二個問題:
定義概念:
孤單堆:只有一根火柴的堆
充裕堆:有兩根或兩根以上火柴的堆
t態:所有堆火柴數異或值為0
s態:所有堆火柴數異或值大於0
t0,s0:所有堆為孤單堆的t/s情形
t1,s1:有乙個充裕堆的t/s情形
t2,s2:有兩個或以上充裕堆的t/s情形
事實上,孤單堆的根數異或只會影響二進位制的最後一位,但充裕堆會影響高位(非最後一位)。乙個充裕堆,高位必有一位不為0,則所有根數異或不為0,故t1態實際上不存在。
[定理5]:s0態,即僅有奇數個孤單堆,必敗。t0態必勝。
證明:s0態,其實就是每次只能取一根。每次第奇數根都由己取,第偶數根都由對 方取,所以最後一根必己取。敗。同理, t0態必勝
[定理6]:s1態,只要方法正確,必勝。
證明:若此時孤單堆含奇數個火柴,把充裕堆取完;否則,取成一根。這樣,就變成奇數個孤單堆,由對方取。由定理5,對方必輸。己必勝。 #
[定理7]:s2態不可轉一次變為t0態。
證明:充裕堆數不可能一次由2變為0。得證。
[定理8]:s2態可一次轉變為t2態。
證明:由定理1,s態可轉變為t態,s態可一次轉變為t態,又由定理6,s2態不可轉一次變為t0態,所以轉變的t態為t2態。
[定理9]:t2態,只能轉變為s2態或s1態。
證明:由定理2,t態必然變為s態。由於充裕堆數不可能一次由2變為0,所以此時的s態不可能為s0態。命題得證。
[定理10]:s2態,只要方法正確,必勝.
證明:方法如下:
1) s2態,就把它變為t2態。(由定理8)
2) 對方只能t2轉變成s2態或s1態(定理9)
若轉變為s2, 轉向1)
若轉變為s1, 這己必勝。(定理5)
[定理11]:t2態必輸。
證明:同10。
綜上所述,對於anti-sg遊戲:
必輸態有: t2,s0
必勝態: s2,s1,t0.
下面的討論中,若不特殊說明,都是對sg遊戲討論,即取走最後一根的一方勝利。
將組合遊戲抽象為有向圖
每個位置為有向圖的乙個節點
每種可行操作為有向圖的一條路徑
我們就在有向圖的頂點上定義sg函式
首先定義mex(minimal excludant)運算,這是施加於乙個集合的運算,表示最小的不屬於這個集合的非負整數。
例如mex=3、mex=0、mex{}=0
對於乙個給定的有向無環圖,定義關於圖的每個頂點的sprague-garundy函式g如下
g(x)=mex。
每個sg值對應nim遊戲每堆石子的初始數量
將所有sg值異或,類同於將nim遊戲的所有初態異或
sg定理(sprague-grundy theorem):
g(g)=g(g1)^g(g2)^…^g(gn)。
遊戲的和的sg函式值是它的所有子遊戲的sg函式值的異或。
對應第一種取火柴遊戲的話,每個子遊戲的sg值就是各堆得火柴數,遊戲的和的sg值就是子遊戲的sg值得異或。
所有的終結點sg值為0(因為它的後繼集合是空集)
sg為0的頂點,它的所有後繼y都滿足sg不為0
對於乙個sg不為0的頂點,必定存在乙個後繼滿足sg為0
滿足組合遊戲性質
所有sg為0定點對應p(必敗)點,sg大於0頂點對應n(必勝)點
每次取得數量不限,那麼每堆的sg值即為該堆得石子數。
取第i堆的話,其他堆異或的結果為b,那麼令(ai-x) xor b==0時,即從ai中取走x可以留給對手乙個必敗態,若此時x用cin和cout 會超時。
亦或有這樣的性質:a ^ b ^ a = b
#include #include using namespace std;
const int max_n = 200000 + 100;
int m,sum;
int arr[max_n];
int main()
if(sum == 0)
//cout << "yes" << endl;
printf("yes\n");
for(int i = 0;i < m;i++)
}return 0;
}
HDU 2176 取 m堆 石子遊戲
hdu 2176 取 m堆 石子遊戲 problem description m堆石子,兩人輪流取.只能在1堆中取.取完者勝.先取者負輸出no.先取者勝輸出yes,然後輸出怎樣取子.例如5堆 5,7,8,9,10先取者勝,先取者第1次取時可以從有8個的那一堆取走7個剩下1個,也可以從有9個的中那一堆...
HDU2176取 m堆 石子遊戲
hdu2176取 m堆 石子遊戲 problem description m堆石子,兩人輪流取.只能在1堆中取.取完者勝.先取者負輸出no.先取者勝輸出yes,然後輸出怎樣取子.例如5堆 5,7,8,9,10先取者勝,先取者第1次取時可以從有8個的那一堆取走7個剩下1個,也可以從有9個的中那一堆取走...
HDU 2176 取 m堆 石子遊戲(博弈)
思路 乙個經典的nim博弈 includeusing namespace std const int maxn 200000 50 int a maxn int main if sum 0 printf no n else printf yes n int res for int i 1 i n i...