HDU 2176 取 m堆 石子遊戲

2021-06-21 00:15:13 字數 4623 閱讀 9896

尼姆博弈。

講解:有三堆各若干個物品,兩個人輪流從某一堆取任意多的物品,規定每次至少取乙個,多者不限,最後取光者得勝。

這種情況最有意思,它與二進位制有密切關係,我們用(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...