博弈——sg函数
Nim游戲:
? ?1. 一個狀態(tài)是必敗狀態(tài)當且僅當它的所有后繼都是必勝狀態(tài)。
2. 一個狀態(tài)是必勝狀態(tài)當且僅當它至少有一個后繼是必敗狀態(tài)。
對于Nim游戲來說,早有科學家給出了一個定理(Bouton定理):狀態(tài)(x1,x2.....xn)為必敗狀態(tài)當且僅當x1^x2^......^xn= 0,即把所有數進行異或和操作,也稱Nim sum。【能夠證明,當Nim sum為0 時為必敗狀態(tài),非0 時為必勝狀態(tài),這是因為,當前狀態(tài)為0 時,進行的某個操作總能使Nim sum變?yōu)榉?(因為改變任何一個數字(即任何一堆石子),它的二進制形式會有一位或多位的變化,此時原本各位上都為0 的Nim sum就會有所變動(某些位會變成1)),即所有后繼都是必勝狀態(tài)了;當前狀態(tài)為非0 時,必定會有某個操作能使Nim sum變?yōu)?(只需在Nim sum二進制上那些為1的位上面著手即可),即一定有一個后繼狀態(tài)為必敗態(tài)。這就是Bouton定理。】
Bouton定理實質上是SG定理的具體應用。什么是SG定理呢?
SG定理:
Sprague-Grundy定理(SG定理):游戲和的SG函數等于各個游戲SG函數的Nim和。這樣就可以將每一個子游戲分而治之,從而簡化了問題。而Bouton定理就是Sprague-Grundy定理在Nim游戲中的直接應用,因為單堆的Nim游戲 SG函數滿足 SG(x) = x。
對于SG定理:
首先定義mex(minimal excludant)運算,這是施加于一個集合的運算,表示最小的不屬于這個集合的非負整數。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。
這一步應該是非常簡單的,就是定義了新的運算為mex。
對于任意狀態(tài) x , 定義 SG(x) = mex(S),其中S是 x 后繼狀態(tài)的SG函數值的集合(就是上述mex中的數值)。最后返回值(也就是SG(X))為0為必敗點,不為零必勝點。
進一步解釋一下S,就是題意中給出的可以移動的次數。舉個例子來說,一堆石子,每次只能拿1,3,5,7個,那么S數組就是1,3,5,7。
假如說是在一個游戲中有多個石子堆該怎么辦了。我們只需要把對每個石子堆進行sg函數的調用,將得到的所有的值進行異或。得出來的結果為0則該情形為必敗態(tài)。否則為必勝態(tài)。
#include<cstdio> #include <iostream> #include <cstring> using namespace std; const int MAX_N = 100; int sg[MAX_N];//sg函數 bool vis[MAX_N];//標記數組void solve(int n) {memset(vis, false, sizeof(vis));for (int i = 0; i < n; ++i)vis[sg[i]] = true;for (int i = 1; i <= n; ++i)//因為可以分成兩堆,如果三堆,就寫三重循環(huán)for (int j = 1; j <= n; ++j) {if (i + j == n) vis[sg[i] ^ sg[j]] = true;}int i;for (i = 0; ; ++i)//沒有i < n,如果都不成立,最后i = nif (!vis[i]) break;sg[n] = i;cout << "sg[" << n << "]=" << i << endl; }?
總結
- 上一篇: js总结:对于字符串的切割截取和合并
- 下一篇: APB协议学习