SG函式求解 NIM遊戲先手必勝必敗問題

2021-09-26 01:20:54 字數 3582 閱讀 1631

nim遊戲:

兩人玩家,給定狀態之間轉移規則,每個人輪流移動,最終得出勝負。

設p為必敗點,n為必勝點

精髓:能到達必敗點的所有點都為必勝點,一般解題都是先找到乙個必敗點,然後由此點推必勝點

若題目中只討論一堆物品 然後讓判斷先手必勝還是必敗,一般就用乙個陣列sg[n]打表,其中n是該物品的數量,通過遞推求出所有範圍內的sg的值,為0時必敗,為1時必勝

1.對一類題目,兩人輪流抓牌類,每次抓取方式有多種(斐波那契數、冪函式等可用陣列訪問)

定義mex運算,表示最小的不屬於這個集合的非負整數,運用sg打表

例如:mex=3 mex=0 mex{}=0

對於任意狀態的x,定義sg(x)=mex(s) ,其中s是x後繼狀態的sg函式值的集合,一般情況下我們會開乙個s陣列,其中它的下標表示在當前for迴圈i下,取過一次之後後繼狀態的sg函式值。可以通過將這些後繼狀態得到的sg函式值全部標記,然後後續遍歷s陣列,找出最小的未被標記的值就作為找到的mex(s).

什麼是x的後繼狀態? 例如取石子,每次有多種取法,取完之後的狀態就是x的後繼狀態,因此有多個後繼狀態

例題1:作為計算機學院的學生,kiki和cici打牌的時候可沒忘記專業,她們打牌的規則是這樣的:

1、 總共n張牌;

2、 雙方輪流抓牌;

3、 每人每次抓牌的個數只能是2的冪次(即:1,2,4,8,16…)

4、 抓完牌,勝負結果也出來了:最後抓完牌的人為勝者;

假設kiki和cici都是足夠聰明(其實不用假設,哪有不聰明的學生~),並且每次都是kiki先抓牌,請問誰能贏呢?

輸入資料報含多個測試用例,每個測試用例佔一行,包含乙個整數n(1<=n<=1000)。

如果kiki能贏的話,請輸出「kiki」,否則請輸出「cici」,每個例項的輸出佔一行。

#include

#include

#include

#include

using namespace std;

const

int n =

1005

;int m,n;

int sg[n]

,f[n]

,s[n]

;voidff(

)}void

getsg

(int n)

//打表

for(

int j=0;

;j++

)//然後遍歷s陣列,找到第乙個沒有被標記的值,就是不存在於mex的值,即為該輪迴圈sg[i]的值}}

}int

main()

}

2.一般題目均是先找到一必敗點,然後逐漸往前推,也是打表

**例題:**輸入乙個數字字串,兩人輪流執行兩個操作中的任意乙個操作,最後不能執行操作的人敗

(1) 將任意一位(個十百…)上面的數減小

(2) 將任意乙個0後面的數刪除(包括0)

由題意可知1是必敗點,則從1開始往後推打表,sg[x],x指的就是該字串轉為的數字

#include

#include

#include

#define ll long long

using namespace std;

const

int maxn=

1e6+7;

int sg[maxn]

;int

getlen

(int x)

return len;

}void

getsg

(int n)

k*=10

;}//必敗點的任意一位數字增加一點,都是必勝點 這兩個for迴圈從個位開始,然後增加至9為止,依次十位,百位.....

k=1;while

(len<6)

}int

main()

char s[15]

;while(~

scanf

("%s"

,s))

return0;

}

3.有的通過遞迴,但還是先找必敗點

有多個容器,每個容器都有一定的容量和原有石子數,現在兩個人輪流在任意容器放石子,規定每次放的數量不能超過原有石子數的平方。問先手勝還是先手敗

#include

#include

#include

using namespace std;

intsg

(int n,

int m)

if(m>x)

return n-m;

else

if(m==x)

return0;

else

return

sg(x,m);}

intmain()

printf

("case %d:\n"

,k);

k++;if

(sum)

printf

("yes\n");

else

printf

("no\n");

}return0;

}

洛谷p1290 歐幾里得的遊戲

歐幾里德的兩個後代stan和ollie正在玩一種數字遊戲,這個遊戲是他們的祖先歐幾里德發明的。給定兩個正整數m和n,從stan開始,從其中較大的乙個數,減去較小的數的正整數倍,當然,得到的數不能小於0。然後是ollie,對剛才得到的數,和m,n中較小的那個數,再進行同樣的操作……直到乙個人得到了0,他就取得了勝利。下面是他們用(25,7)兩個數遊戲的過程:

start:25 7

stan:11 7

ollie:4 7

stan:4 3

ollie:1 3

stan:1 0

stan贏得了遊戲的勝利。

現在,假設他們完美地操作,誰會取得勝利呢?

題解:同樣先找必敗點,可知(3 1)局面是必勝點,那麼(4 3)局面是必敗點,那麼(4 7)局面是必勝點,(11 7)局面是必敗點,原因是對於兩個數,乙個數除以另乙個數為1,那麼每次操作都是固定的:(大的數-小的數) 因此對應局面也是相反的

對於兩個數,乙個數除以另乙個數大於1的,仔細觀察其後繼局面 如(25 7),其後記局面可以為 (18 7) (11 7) 也可以為(7 4)

可知(11 7)與(7,4)必定是兩個相反的局面,因此sg函式值必定有乙個為0 ,所以(25 7)這個局面的sg函式值必定大於0,即一定是必勝點,因此對於兩個數乙個數除以另乙個數大於1的,此局面就是必勝點

**如下:

#include

#include

#include

#include

using namespace std;

bool sg

(int n,

int m)

intmain()

return0;

}

組合遊戲(Nim遊戲) SG函式

sg為0的點 必敗點 能到達的肯定都是sg不為0的點 必勝點 sg不為0的點 必勝點 一定能通過某種方式到達sg為0的點 必敗點 組合遊戲典型例題 給定n堆石子以及乙個由k個不同正整數構成的數字集合s。現在有兩位玩家輪流操作,每次操作可以從任意一堆石子中拿取石子,每次拿取的石子數量必須包含於集合s,...

nim遊戲和SG函式

1.無法進行任何移動的局面 terminal position 是p position.先手必敗 2.可以移動到p position的是n position.先手必勝 3.所有可行的移動都導致n position的是p position.先手必敗 mex minimal excludant 運算 對...

Nim 遊戲 SG 函式 遊戲的和

nim遊戲是組合遊戲 combinatorial games 的一種,準確來說,屬於 impartial combinatorial games 以下簡稱icg 滿足以下條件的遊戲是icg 可能不太嚴謹 1 有兩名選手 2 兩名選手交替對遊戲進行移動 move 每次一步,選手可以在 一般而言 有限的...