SG函數資料(入門必備)

以上內容轉自某大牛博客 http://qing.weibo.com/2126316852/7ebd053433000viz.html

入門一:

首先來玩個遊戲,引用杭電課件上的:

(1) 玩家:2人;

(2) 道具:23張撲克牌;

(3) 規則:

遊戲雙方輪流取牌;
      每人每次僅限於取1張、2張或3張牌;
      撲克牌取光,則遊戲結束;
      最後取牌的一方爲勝者。

      想一下。。

      首先申明一點,博弈的討論是在大家都玩的最好的情況下討論的。(如果2個玩家智商有差別,那就沒法討論了~~~~開個玩笑哈。)

      介紹概念:P點 即必敗點,某玩家位於此點,只要對方無失誤,則必敗;

                        N點 即必勝點,某玩家位於此點,只要自己無失誤,則必勝。

定理:

     一、 所有終結點都是必敗點P(上游戲中,輪到誰拿牌,還剩0張牌的時候,此人就輸了,因爲無牌可取);

    二、所有一步能走到必敗點P的就是N點;

    三、通過一步操作只能到N點的就是P點;

    自己畫下圖看看。

    x 0  1  2  3  4  5  6  7  8  9  10。。。

posP   N N  N  P N  N  N  P N   N 。。。

    所以若玩家甲位於N點。只要每次把P點讓給對方,則甲必勝;

   反之,若玩家甲位於P點,他每次只能走到N點,而只要乙每次把P點讓給甲,甲必敗;

    這裏好好理解下;

   如果上面的理解的。請解決下面的題目:HDU 1846   2147(注意題目限制內存)(先2道練練手,做不出的話提示:找規律)

    接下來介紹Nim遊戲(同樣引用杭電上的,懶的打字)

   1.有兩個玩家;
   2.  有三堆撲克牌(比如:可以分別是    579張);
  3. 遊戲雙方輪流操作;
  4. 玩家的每次操作是選擇其中某一堆牌,然後從中取走任意張;
   5.最後一次取牌的一方爲獲勝方;

   想一會:

   還記得剛纔說的P點和N點嗎?P:必敗點,N:必勝點

   先給出結論,這裏要用到位運算,異或:^

    遊戲的某個位置(x1,x2,x3) x1,x2,x3表示3堆的個數。當且僅當 x1^x2^x3=0時,此點纔是必敗點P

    結論可以推廣到一般情況,即有n堆,(x1,x2,x3,...xn) 當且僅當x1^x2^x3...^xn=0時,此點纔是必敗點P

    如要看證明過程,鏈接在此    http://acm.hdu.edu.cn/forum/read.php?fid=9&tid=10617,看不懂的可以問 我(汗。。)

 練習:HDU 2188  2149   (做不出的話先看下面的,然後多思考)

   下面介紹sg函數(解決博弈問題的王道)

   sg Graph Game,把博弈遊戲抽象成有向無環圖

(1) 有向無環圖
      (2) 玩家1先移動,起點是x0
      (3) 兩個玩家輪流移動
      (4) 對於頂點x, 玩家能夠移動到的頂點集記爲F(x).
      (5) 不能移動的玩家會輸掉遊戲

首先定義mex(minimal excludant)運算,這是施加於一個集合的運算,表示最小的不屬於這個集合的非負整數。例如mex{0,1,2,4}=3、 mex{2,3,5}=0mex{}=0

定義一個圖的Sprague-Grundy函數(X,F)是定義在X上的非負函數g(x),並且滿足:
       g(x) = mex{g(y) : yF(x)}

看到這裏先好好理解一下sg值是怎麼求的;

如果在取子游戲中每次只能取{1,2,3},那麼各個數的SG值是多少?

x      0 1 2 3 4 5 6 7 8 9 10 11 12 13 14. . .
g(x) 0 1 2 3 0 1 2 3 0 1  2   3   0   1   2. . .
看看這個和上面那個圖的規律:

  P-即令 g(x) = 0 的 點!
 N-即令 g(x) > 0 的 點!

練習 HDU 1847  1849  1850 (做不出的話先看下面的,然後多思考)

最後看下組合博弈,就是把簡單的遊戲組合起來,比如3堆的可以看成3個一堆的遊戲。

 定理:

假設遊戲 GiSG函數是gi, i=1,…,n, 
G = G1   …   Gn 的 SG函數是
g(x1,…,xn) = g1(x1)⊕…⊕gn(xn).

其中那個符合就是異或^

看看是不是和Nim遊戲的結論差不多?

如果想理解原理鏈接在此:http://www.cnitblog.com/weiweibbs/articles/42735.html

看完以上的,做完以下的練習。能理解完基本差不多可以算入門了:

HDU 1848 1517 1536(做不出就思考,思考,多看幾遍)

 

上一期的文章裏我們仔細研究了Nim遊戲,並且瞭解了找出必勝策略的方法。但如果把Nim的規則略加改變,你還能很快找出必勝策略嗎?比如說:有n堆石子,每次可以從第1堆石子裏取1顆、2顆或3顆,可以從第2堆石子裏取奇數顆,可以從第3堆及以後石子裏取任意顆……這時看上去問題複雜了很多,但相信你如果掌握了本節的內容,類似的千變萬化的問題都是不成問題的。

現在我們來研究一個看上去似乎更爲一般的遊戲:給定一個有向無環圖和一個起始頂點上的一枚棋子,兩名選手交替的將這枚棋子沿有向邊進行移動,無法移動者判負。事實上,這個遊戲可以認爲是所有Impartial Combinatorial Games的抽象模型。也就是說,任何一個ICG都可以通過把每個局面看成一個頂點,對每個局面和它的子局面連一條有向邊來抽象成這個有向圖遊戲。下面我們就在有向無環圖的頂點上定義Sprague-Garundy函數。

首先定義mex(minimal excludant)運算,這是施加於一個集合的運算,表示最小的不屬於這個集合的非負整數。例如mex{0,1,2,4}=3mex{2,3,5}=0mex{}=0

對於一個給定的有向無環圖,定義關於圖的每個頂點的Sprague-Garundy函數g如下:g(x)=mex{ g(y) | yx的後繼}

來看一下SG函數的性質。首先,所有的terminal position所對應的頂點,也就是沒有出邊的頂點,其SG值爲0,因爲它的後繼集合是空集。然後對於一個g(x)=0的頂點x,它的所有後繼y都滿足g(y)!=0。對於一個g(x)!=0的頂點,必定存在一個後繼y滿足g(y)=0

以上這三句話表明,頂點x所代表的postionP-position當且僅當g(x)=0(跟P-positioin/N-position的定義的那三句話是完全對應的)。我們通過計算有向無環圖的每個頂點的SG值,就可以對每種局面找到必勝策略了。但SG函數的用途遠沒有這樣簡單。如果將有向圖遊戲變複雜一點,比如說,有向圖上並不是只有一枚棋子,而是有n枚棋子,每次可以任選一顆進行移動,這時,怎樣找到必勝策略呢?

讓我們再來考慮一下頂點的SG值的意義。當g(x)=k時,表明對於任意一個0<=i<k,都存在x的一個後繼y滿足g(y)=i。也就是說,當某枚棋子的SG值是k時,我們可以把它變成0、變成1……、變成k-1,但絕對不能保持k不變。不知道你能不能根據這個聯想到Nim遊戲,Nim遊戲的規則就是:每次選擇一堆數量爲k的石子,可以把它變成0、變成1……、變成k-1,但絕對不能保持k不變。這表明,如果將n枚棋子所在的頂點的SG值看作n堆相應數量的石子,那麼這個Nim遊戲的每個必勝策略都對應於原來這n枚棋子的必勝策略!

對於n個棋子,設它們對應的頂點的SG值分別爲(a1,a2,...,an),再設局面(a1,a2,...,an)時的Nim遊戲的一種必勝策略是把ai變成k,那麼原遊戲的一種必勝策略就是把第i枚棋子移動到一個SG值爲k的頂點。這聽上去有點過於神奇——怎麼繞了一圈又回到Nim遊戲上了。

其實我們還是隻要證明這種多棋子的有向圖遊戲的局面是P-position當且僅當所有棋子所在的位置的SG函數的異或爲0。這個證明與上節的Bouton's Theorem幾乎是完全相同的,只需要適當的改幾個名詞就行了。

剛纔,我爲了使問題看上去更容易一些,認爲n枚棋子是在一個有向圖上移動。但如果不是在一個有向圖上,而是每個棋子在一個有向圖上,每次可以任選一個棋子(也就是任選一個有向圖)進行移動,這樣也不會給結論帶來任何變化。

所以我們可以定義有向圖遊戲的和(Sum of Graph Games):設G1G2……Gnn個有向圖遊戲,定義遊戲GG1G2……Gn的和(Sum),遊戲G的移動規則是:任選一個子遊戲Gi並移動上面的棋子。Sprague-Grundy Theorem就是:g(G)=g(G1)^g(G2)^...^g(Gn)。也就是說,遊戲的和的SG函數值是它的所有子游戲的SG函數值的異或。

再考慮在本文一開頭的一句話:任何一個ICG都可以抽象成一個有向圖遊戲。所以“SG函數遊戲的和的概念就不是侷限於有向圖遊戲。我們給每個ICG的每個position定義SG值,也可以定義nICG的和。所以說當我們面對由n個遊戲組合成的一個遊戲時,只需對於每個遊戲找出求它的每個局面的SG值的方法,就可以把這些SG值全部看成Nim的石子堆,然後依照找Nim的必勝策略的方法來找這個遊戲的必勝策略了!

回到本文開頭的問題。有n堆石子,每次可以從第1堆石子裏取1顆、2顆或3顆,可以從第2堆石子裏取奇數顆,可以從第3堆及以後石子裏取任意顆……我們可以把它看作3個子遊戲,第1個子遊戲只有一堆石子,每次可以取123顆,很容易看出x顆石子的局面的SG值是x%4。第2個子遊戲也是隻有一堆石子,每次可以取奇數顆,經過簡單的畫圖可以知道這個遊戲有x顆石子時的SG值是x%2。第3個遊戲有n-2堆石子,就是一個Nim遊戲。對於原遊戲的每個局面,把三個子游戲的SG值異或一下就得到了整個遊戲的SG值,然後就可以根據這個SG值判斷是否有必勝策略以及做出決策了。其實看作3個子遊戲還是保守了些,乾脆看作n個子遊戲,其中第12個子遊戲如上所述,第3個及以後的子游戲都是“1堆石子,每次取幾顆都可以,稱爲任取石子游戲,這個超簡單的遊戲有x顆石子的SG值顯然就是x。其實,n堆石子的Nim遊戲本身不就是n任取石子游戲的和嗎?

所以,對於我們來說,SG函數與遊戲的和的概念不是讓我們去組合、製造稀奇古怪的遊戲,而是把遇到的看上去有些複雜的遊戲試圖分成若干個子游戲,對於每個比原遊戲簡化很多的子游戲找出它的SG函數,然後全部異或起來就得到了原遊戲的SG函數,就可以解決原遊戲了。這種分而治之的思想在下一節介紹的翻硬幣遊戲中將被應用得淋漓盡致。還是敬請期待。


例題:hdu 1536 S-Nim

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>

using namespace std;

int a[110];
int sg[10010];

int n;
int GetSg(int v)
{

    int hash[110]={0};//用於尋找最小的SG值做標記
    int temp;
    for(int i=0;i<n;i++)
    {
        temp=v-a[i];
        if(temp<0)
            break;
        if(sg[temp]==-1)//尋找最小的SG數
        {
            sg[temp]=GetSg(temp);
        }
        hash[sg[temp]]=1;//爲後繼點加上標記
    }
    for(int i=0;;i++)//找到每一個SG[i]的最小SG值
    {
        if(hash[i]==0)
            return i;
    }
}
int main()
{

    while(scanf("%d",&n),n)
    {
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);//能取的數
        sort(a,a+n);
        memset(sg,-1,sizeof(sg));
        sg[0]=0;
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int m,v,ans=0;
            scanf("%d",&m);
            for(int i=0;i<m;i++)
            {
                 scanf("%d",&v);
                 sg[v]=GetSg(v);
                 ans^=sg[v];
            }

            if(ans==0) printf("L");
            else printf("W");

        }
        printf("\n");
    }
}


其他例題: hdu 1848....


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章