取石子游戲之巴什博弈

下面這段來自白白の屋的文章的一段:

巴什博弈:只有一堆n個物品,兩個人輪流從這堆物品中取物,規定每次至少取一個,最多取m個。最後取光者得勝。

    顯然,如果n=m+1,那麼由於一次最多隻能取m個,所以,無論先取者拿走多少個,後取者都能夠一次拿走剩餘的物品,後者取勝。因此我們發現瞭如何取勝的法則:如果
n=(m+1)r+s,(r爲任意自然數,s≤m),那麼先取者要拿走s個物品,如果後取者拿走k(≤m)個,那麼先取者再拿走m+1-k個,結果剩下(m+1)(r-1)個,以後保持這樣的取法,那麼先取者肯定獲勝。總之,要保持給對手留下(m+1)的倍數,就能最後獲勝。那麼這個時候只要n%(m+1)!=0,先取者一定獲勝

    這個遊戲還可以有一種變相的玩法:兩個人輪流報數,每次至少報一個,最多報十個,誰能報到100者勝。

    分析此類問題主要放法是:P/N分析:

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

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

     三個定理:

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

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

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

巴什博弈的一個最重要的特徵就是只有一堆。然後就在其中改,要麼在範圍內不規定個數,要麼就規定只能取幾個,再要麼就倒過來,畢竟是最簡單的博弈,代碼相對而言較短額~

例題1:NYOJ 23(取石子游戲一),巴什博弈,只要n%(m+1)!=0,則先取者一定獲勝。

#include<iostream>
using namespace std; 
int main()
{   int n,m,Case;
    cin>>Case;
    while(Case--)
    {   cin>>n>>m;
        cout<<(n%(m+1)?"Win":"Lose")<<endl;
    }
    return 0;
}

例題2:HDU 2149,英語標題額,原來是中文題。反過來就是一樣的啦,只是取數時的規律是:如果M%(N+1)!=0,那麼第一個取的數就是M%(N+1),留給對手的是(N+1)的倍數,還有就是M<N的情況,不說你也懂,開始寫了sort的,但後來一看可以不要,代碼:

#include<iostream>
using namespace std;
int main()
{   int n,m;
    while(scanf("%d%d",&m,&n)!=EOF)
    {   int sum=0;
        if(m%(n+1)==0) cout<<"none";
        else
        {   if(m%(n+1))  cout<<m%(n+1); //直接取餘數 
            if(n>=m)
            {   for(int i=m+1;i<=n;i++)
                    cout<<" "<<i;
            } 
        }
        cout<<endl;
    }
    return 0;
}

題3:HDU 1847,尋找必敗態,n%3=0則Cici贏,否則Kiki贏。

分析:(1)、若是留給Cici的是3,那麼Cici只能取1個或2個,所以再輪到Kiki取的話必贏。

            (2)、若是給Cici留下的是3的倍數,假設爲3n(n=1,2,3,..),那麼無論Cici取什麼數,剩餘的數一定可以寫成3m+1或者3m+2(m<n)的形式,那麼只要Kiki再取的時候留給Cici的仍然是3的倍數的話,就必勝了。代碼略。

當然這種題目可以直接先枚舉前面幾個數,就能找到規律啦~
 

 

 

 

 

 

 

 

 

 

 

 



 

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