【集训笔记】博弈论相关知识【HDOJ 1850【HDOJ2147
以下資料來自:http://blog.csdn.net/Dinosoft/article/details/6795700 http://qianmacao.blog.163.com/blog/static/203397180201222945212647/
http://blog.csdn.net/qinmusiyan/article/details/7950642#
HDU 1850 Being a Good Boy in Spring Festival
下面是一個二人小游戲:桌子上有M堆撲克牌;每堆牌的數(shù)量分別為Ni(i=1…M);
兩人輪流進行;每走一步可以任意選擇一堆并取走其中的任意張牌;
桌子上的撲克全部取光,則游戲結(jié)束;最后一次取牌的人為勝者。
現(xiàn)在我們不想研究到底先手為勝還是為負,我只想問大家:
——“先手的人如果想贏,第一步有幾種選擇呢?”
Input
輸入數(shù)據(jù)包含多個測試用例,每個測試用例占2行,首先一行包含一個整數(shù)M(1<M<=100),表示撲克牌的堆數(shù),緊接著一行包含M個整數(shù)Ni(1<=Ni<=1000000,i=1…M),分別表示M堆撲克的數(shù)量。M為0則表示輸入數(shù)據(jù)的結(jié)束。
Output
如果先手的人能贏,請輸出他第一步可行的方案數(shù),否則請輸出0,每個實例的輸出占一行。
Sample Input
3
5 7 9
0
Sample Output
1
算法分析:
1、如果a1^a2^a3^...^an =0(即:nim - sum =0),說明先手沒有必勝策略,方法數(shù)肯定為0;
2、假設(shè)先手有必勝策略。
問題則轉(zhuǎn)化為=>在任意一堆拿走任意K張牌,并且剩下所有堆nim - sum =0(P-position)的方案總數(shù)。
①現(xiàn)在我們先看一個例子(5、7、9),并假設(shè)從第一堆取任意K張牌。
排除第一堆牌的nim - sum 為7^9=14
0111
^1001
--------------
1110
如果要使所有堆的nim-sum =0成立,則第一堆取掉K張以后必定為1110,因為X^X=0.
所以要觀察5- K =15(K >0)成立,此例子(在第一堆取任意K張牌)明顯不成立。
但不代表在第二或第三堆取任意K張牌的解不成立。
②現(xiàn)在看第二例子(15、7、9),并假設(shè)從第一堆取任意K張牌。
排除第一堆的nim - sum 為7^9=14,和第一個例子相同,所以問題變?yōu)橛^察15- K =14(K >0)是否成立。
顯然這個例子成立。
3、總結(jié)得出:
在任意一堆拿任意K張牌,并且所有堆的nim-sum =0成立的條件為:
排除取掉K張牌的那一堆的nim-sum必須少于該堆牌上的數(shù)量(例子②),
否則不能在此堆上取任意K張牌所有堆的nim-sum =0成立(例子①)
故總方案數(shù)為(在任意一堆拿任意K張牌,并且所有堆的nim-sum =0成立)的總數(shù)。
1 #include <stdio.h>
2
3 int main(){
4 int i,n,sum,a[10001];
5 while(EOF != scanf("%d",&n)){
6 if(n == 0)
7 break;
8 sum = 0;
9 for(i = 0;i < n;i++){
10 scanf("%d",&a[i]);
11 sum ^= a[i];
12 }
13 if(sum == 0)
14 printf("0
");
15 else{
16 int count = 0;
17 for(i=0;i<n;i++){
18 sum ^= a[i];
19 if(a[i] > sum)
20 count++;
21 sum ^= a[i];
22 }
23 printf("%d
",count);
24 }
25 }
26 return 0;
27 }
hdu-2147:kiki's game
Recently kiki has nothing to do. While she is bored, an idea appears in his mind, she just playes the checkerboard game.The size of the chesserboard is n*m.First of all, a coin is placed in the top right corner(1,m). Each time one people can move the coin into the left, the underneath or the left-underneath blank space.The person who can't make a move will lose the game. kiki plays it with ZZ.The game always starts with kiki. If both play perfectly, who will win the game? Input Input contains multiple test cases. Each line contains two integer n, m (0<n,m<=2000). The input is terminated when n=0 and m=0. Output If kiki wins the game printf "Wonderful!", else "What a pity!". Sample Input 5 3 5 4 6 6 0 0
Promblem description
P點:就是P個石子的時候,對方拿可以贏(自己輸?shù)?
N點:就是N個石子的時候,自己拿可以贏
現(xiàn)在關(guān)于P,N的求解有三個規(guī)則
(1):最終態(tài)都是P
(2):按照游戲規(guī)則,到達當(dāng)前態(tài)的前態(tài)都是N的話,當(dāng)前態(tài)是P
(3):按照游戲規(guī)則,到達當(dāng)前態(tài)的前態(tài)至少有一個P的話,當(dāng)前態(tài)是N
題意:
在一個m*n的棋盤內(nèi),從(1,m)點出發(fā),每次可以進行的移動是:左移一,下移一,左下移一。然后kiki每次先走,判斷kiki時候會贏(對方無路可走的時候)。
我們可以把PN狀態(tài)的點描繪出來::
代碼很簡單,只需要判斷奇偶
|
J.xiaodao 我愛你! |
|||||
|
|||||
|
Description |
|||||
|
自從見到xiaodao的第一眼起,我就不可救藥的愛上了她。 xiaodao——如果四個頂點有石子,那么你可以把石子都拿走(不能剩下),如果沒有石子你得再選一次,直到有拿走石子為止。 xiaodao——我們規(guī)定,如果誰沒有石子拿了,誰就輸,聽明白了么! |
|||||
|
Input |
|||||
|
第一行是一個整數(shù)T代表以下T組數(shù)據(jù)。 每組數(shù)據(jù)占一行,兩個整數(shù)N , M。(注意,當(dāng)N * M為奇數(shù)的時候中心的那一個石子已經(jīng)被拿走了) |
|||||
|
Output |
|||||
|
輸出一行,如果是DS獲勝那么輸出"DS",否則輸出"xiaodao" .(不帶引號) |
|||||
|
Sample Input |
|||||
|
2 2 2 3 3 |
|||||
|
Sample Output |
|||||
|
DS xiaodao |
|||||
|
Hint |
|||||
|
1.以下是兩個樣例的游戲開始的示意圖 2.對于非法情況的界定 如圖,對于下圖的N=9,M=9情況,√的代表合法操作,×的代表非合法操作。 非合法操作有兩種——超出邊界或者格子四個頂點沒有石子。 |
代碼很簡短,只需要判斷奇偶性
1 #include<stdio.h>
2 int main(){
3 int t,m,n;
4 scanf("%d",&t);
5 while(t--){
6 scanf("%d%d",&m,&n);
7 if(n%2==0&&m%2==0)
8 printf("DS
");
9 else
10 printf("xiaodao
");
11 }
12 return 0;
13 }
//文縐縐的定義,隨便看看就好
Nim游戲是組合游戲(Combinatorial Games)的一種,準確來說,屬于“Impartial Combinatori Games”(以下簡稱 ICG)。滿足以下條件的游戲是ICG(可能不太嚴謹):
1、有兩名選手;
2、兩名選手交替對游戲進行移動(move),每次一步,選手可以在(一般而言)有限的合法移動集合中任選一種進行移動;
3、對于游戲的任何一種可能的局面,合法的移動集合只取決于這個局面本身,不取決于輪到哪名選手操作、以前的任何操作、骰子的點數(shù)或者其它什么因素;
4、如果輪到某名選手移動,且這個局面的合法的移動集合為空(也就是說此時無法進行移動),則這名選手負。根據(jù)這個定義,很多日常的游戲并非 ICG。例如象棋就不滿
足條件3,因為紅方只能移動紅子,黑方只能移動黑子,合法的移動集合取決于輪到哪名選手操作。
Nim 游戲
定義:有若干堆石子,每堆石子的數(shù)量都是有限的,合法的移動是“選擇一堆石子并拿走若干顆(不能不拿)”,如果輪到某個人時所有的石子堆都已經(jīng)被拿空了,則判負(因為他此刻沒有任何合法的移動)。
當(dāng)然,特殊情況就是只有一堆或者兩堆石子,自己去意淫一下吧。
P-position和N-position
其中P 代表Previous,N 代表Next。 P-position是必敗態(tài),N-position是必勝態(tài)。
必敗(必勝)點屬性
(1) 所有終結(jié)點是必敗點(P點); //容易理解
(2) 從任何必勝點(N點)操作,至少有一種方法可以進入必敗點(P點); //就是那種我們要走的方法
(3)無論如何操作, 從必敗點(P點)都只能進入必勝點(N點). //對手走完又只能把N留給我們
取子游戲算法實現(xiàn)
步驟1:將所有終結(jié)位置標記為必敗點(P點);
步驟2: 將所有一步操作能進入必敗點(P點)的位置標記為必勝點(N點)
步驟3:如果從某個點開始的所有一步操作都只能進入必勝點(N點) ,則將該點標記為必敗點(P點) ;
步驟4: 如果在步驟3未能找到新的必敗(P點),則算法終止;否則,返回到步驟2
/*
上面的說法似乎不太好理解。我簡單講下。顯然我們可以從終結(jié)條件遞推回來。往后往前開始掃描,(終結(jié)狀態(tài)方向為后)
a.如果當(dāng)前是P點,那么一步(向前)可以走到的都是N點
b.如果當(dāng)前點未標明P/N屬性,那么看看該點向后走是不是都只能到達N點,如果是,那么該點是P點。
c.如果該點是N點,倒無法確定什么。
如果沒辦法標一個點,那么異常結(jié)束。
*/
例題
kiki's game
我是用P N狀態(tài)遞推出來小規(guī)模的數(shù)據(jù)后找規(guī)律的,直接遞推提交爆內(nèi)存。(x,y)中,x和y都是奇數(shù)的話,那么無論怎么移動,x和y中都有至少有一個偶數(shù),而且再移動一步后,都可以變成xy全奇數(shù)。
Nim-Sum
直接說結(jié)論好了。(Bouton's Theorem)對于一個Nim游戲的局面(a1,a2,...,an),
它是P-position 當(dāng)且僅當(dāng)a1^a2^...^an=0,其中^表示異或(xor)運算。
根據(jù)定義,證明一種判斷position的性質(zhì)的方法的正確性,只需證明三個命題:
1、這個判斷將所有terminal position 判為P-position;
2、根據(jù)這個判斷被判為N-position 的局面一定可以移動到某個 P-position;
3、根據(jù)這個判斷被判為 P-position 的局面無法移動到某個P-position。
第一個命題顯然,terminal position 只有一個,就是全 0,異或仍然是0。
第二個命題,對于某個局面(a1,a2,...,an),若 a1^a2^...^an!=0,一定存在某個合法的移動,將ai 改變成 ai'后滿足 a1^a2^...^ai'^...^an=0。不妨設(shè) a1^a2^...^an=k,則一定存在某個 ai,它的二進制表示在k的最高位上是 1(否則k 的最高位那個 1是怎么得到的)。這時ai^k<ai一定成立。則我們可以將 ai改變成ai'=ai^k,此時a1^a2^...^ai'^...^an=a1^a2^...^an^k=0。
//注意可以拿走若干顆,數(shù)目不限哦
第三個命題,對于某個局面(a1,a2,...,an),若 a1^a2^...^an=0,一定不存在某個合法的移動,將 ai 改 變 成 ai' 后滿足 a1^a2^...^ai'^...^an=0 。 因 為 異 或 運 算 滿 足 消 去 率 , 由a1^a2^...^an=a1^a2^...^ai'^...^an 可以得到 ai=ai'。所以將 ai 改變成 ai'不是一個合法的移動。證畢。
// 簡單理解,異或2次可以翻轉(zhuǎn)回來,我們只改一個數(shù)字的話,翻不回來。
例題
Being a Good Boy in Spring Festival
求Nim-Sum,非零才能贏。然后每次從Nim-Sum去掉一堆撲克牌,結(jié)果是否小于這堆撲克牌數(shù),如果能,方法數(shù)+1
ZOJ 3529 A Game Between Alice and Bob
上面強調(diào)了一點,游戲中每次拿走的石頭數(shù)目是不限的,而這道題需要運用技巧進行轉(zhuǎn)換。
求出因子數(shù)即可!可以用dp,然后在篩素數(shù)的時候順便記錄一下其中一個最大的因子。源碼可以看這里:
http://growthinking.com/archives/1777
Sprague-Grundy 函數(shù)
現(xiàn)在我們來研究一個看上去似乎更為一般的游戲:給定一個有向無環(huán)圖和一個起始頂點上的一枚棋子,兩名選手交替的將這枚棋子沿有向邊進行移動,無法移動者判負。事實上,這個游戲可以認為是所有 Impartial Combinatorial Games 的抽象模型。也就是說,任何一個 ICG都可以通過把每個局面看成一個頂點,對每個局面和它的子局面連一條有向邊來抽象成這個“有向圖游戲”。下面我們就在有向無環(huán)圖的頂點上定義 Sprague-Garundy函數(shù)。
mex(minimal excludant)運算
定義表示最小的不屬于這個集合的非負整數(shù)。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
對于一個給定的有向無環(huán)圖,定義關(guān)于圖的每個頂點的 Sprague-Garundy 函數(shù) g 如下:
g(x)=mex{ g(y) | y是 x的后繼 }。
來看一下 SG 函數(shù)的性質(zhì)。首先,所有的 terminal position 所對應(yīng)的頂點,也就是沒有出邊的頂點,其 SG 值為 0,因為它的后繼集合是空集。然后對于一個g(x)=0 的頂點 x,它的所后繼y都滿足 g(y)!=0。對于一個g(x)!=0的頂點,必定存在一個后繼 y滿足g(y)=0。
以上這三句話表明,頂點 x 所代表的 postion 是 P-position 當(dāng)且僅當(dāng) g(x)=0(跟P-positioin/N-position 的定義的那三句話是完全對應(yīng)的)。我們通過計算有向無環(huán)圖的每個頂點,就可以對每種局面找到必勝策略了。
例題
S-Nim
sg函數(shù)小試牛刀,哈哈
總結(jié)一下
一堆石子的游戲 ---->兩堆石子的游戲 ---> Nim游戲 ---> 有向圖
P/N position <----> Nim-Sum <----> SG函數(shù) //想起一個詞 "同構(gòu)"
總結(jié)
以上是生活随笔為你收集整理的【集训笔记】博弈论相关知识【HDOJ 1850【HDOJ2147的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: n2n搭建手记-2-V2
- 下一篇: 0patch 接棒续命 2 年:在微软