HDU1527——取石子游戲(威佐夫博弈)

題目鏈接

       這道題是威佐夫博弈的一道入門題,問的十分簡單,就是套威佐夫博弈的兩個公式即可,因此順帶說說威佐夫博弈,威佐夫博弈和巴什博奕的場景很類似,所以索性就套用我在巴什博奕那篇文章中所描述的的那個場景。有兩個二貨,比賽拿XX(XX可以是任何東西,只要能定量拿走就好),只是這一次他們不再將XX混爲一堆,而是作爲兩堆(兩堆XX的數量均任意個),然後拿走的方式也改爲:  1,從一堆裏拿,可以拿任意數量個。2,從兩堆裏分別拿相等數量個。這兩種方式二選一,但至少拿走一個XX,若誰取走最後一個XX,誰就贏了。是不是場景變得比巴什博奕麻煩了那麼一丟丟啊~~~~

       那麼問題來了,如何取勝呢,,,(以下論述均是我參考了百度百科上的論述所寫的,如果大家覺得寫的太難看,可以直接參照百度百科上的:威佐夫博弈)

       首先,我們標記一下這兩堆石頭:(a,b),其中a表示當前狀態第一堆的數量,b表示當前狀態第二堆的數量,(這裏我要強調一點:就是這兩堆XX它們的價值是等價的,它們是可以互換的,並不一定說第二堆的數量一定比第一堆多,這一點在後續論述中是有一定作用的)

       然後百科上對於(a,b)也給了一個特定的名稱叫做“局勢”,然後給出一些明顯的必敗狀態(也就是當你面對這些狀態時,只要你的對手夠聰明,不犯錯,無論你怎麼拿,你都是必輸的)(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)、...... 、(ak,bk) (k = 0, 1, 2, 3,......)。並稱這些必敗狀態爲“奇異局勢”(至於爲什麼要叫奇異局勢......額......不太清楚,忽略吧~)接下來的工作就是找出這些奇異局勢的特點並總結規律。


       然後就會得到a0=b0=0,ak是未在前面出現過的最小自然數,而 bk= ak + k。然後公式化就得到了奇異局勢的狀態公式:

                                   ak = [ k * (1 + √5) / 2 ]     ,   ([x]表示對x取整,也就是 (int)x )

                                   bk = ak + k


       按百科上所說,奇異局勢有三個性質——


                                性質1:每個自然數都包含在且只包含在一個奇異局勢中。

                                證明:因爲ak爲在其之前的奇異局勢中未出現過的最小的自然數,所以ak的取值一直是保證在之前狀態未出現過的數中的最小值,所以每一個當前狀態的ak都要比之前的狀態的ak要大,即ak>ak-1(k-1是下標),還想不通。。。不要緊,,把k和k-1帶入上面ak的公式,這總能接受吧~~~~但ak不一定比bk-1大,看上面給出的幾組奇異局勢就不難看出。又bk=ak+k>ak-1+(k-1)=bk-1,所以對於任意的奇異狀態(ak,bk)之前的狀態中一定未出現過其中的數字,但ak取值是自動取當前未出現過的最小的數字,所以每一個自然數都一定會出現,故性質得證。

                           

                                 性質2:對任意的奇異局勢,任何合法的操作都會使其成爲非奇異局勢,也就是奇異局勢的所有後繼狀態均爲非奇異局勢。

                                 證明:①若只從一堆裏取XX,那麼另一堆得數量沒變,由性質1知,這個沒變的自然數只會出現在當前的奇異局勢中,所以當另一堆發生變化時,改變後得到的狀態一定是非奇異局勢。

                                            ②若從兩堆裏取相同數量的XX,那麼由於 bk - ak = k (由公式得),所以他們之間的差值是不會變的,又因爲對於任意的奇異局勢它的兩堆之間的差值是唯一值k,所以這種取法後的狀態仍舊是非奇異局勢。故性質得證。


                                 性質3:任何非奇異局勢都可以通過某種合法操作得到奇異局勢,即奇異局勢的所有後繼狀態中存在奇異局勢。

                                 證明:對於任意的一個非奇異局勢(x,y),由性質1知:任何自然數均會出現在一個奇異局勢中,所以要麼 x = ak,要麼 y = b(k ∈ { 0, 1, 2, 3, 4, 5, .......}),所以分類討論:

                                            ①若x = ak,y > bk,那麼y減去(y - bk)即可得到奇異局勢(ak , bk).

                                            ②若x = ak,y < bk,那麼兩堆同時減掉x-a(y-x)  (y-x爲下標),得到奇異局勢(a(y-x) , a(y-x)+y-x).

                                            ③若x > ak,y = bk,那麼x減去(x - ak)即可得到奇異局勢(ak , bk).

                                            ④若x < ak,y = bk,這時又要對該狀況細化分類討論:

                                                                情況(1): x = aj , (j < k),此時從y中拿走(y - bj)即可得到奇異局勢(aj , bj),

                                                                情況(2): x = bj , (j < k),此時從y中拿走(y - aj)即可得到奇異局勢(aj , bj).

                                             這裏的④爲什麼要分類呢?這就要注意上文中我曾提到的強調點,這兩堆是等價值的,也就是情況(2)得到奇異局勢其實是(bj , aj),此時第一堆是比第二堆多的,爲了同意奇異局勢的格式才把它寫成(aj , bj)。所以細化分類討論的其實是對操作後  第一堆多餘第二堆 和 第二堆多餘第一堆 的兩種情況進行討論。這樣性質3也得證。

        好了,解釋了這麼多,回到此題正解,這道題就是套上述的ak和bk的公式,若符合奇異局勢,則先手輸,否則先手勝,輸出對應結果即可。


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

using namespace std;

int main()
{
    //freopen("in.in","r",stdin);
    //freopen("out.out","w",stdout);
    int n, m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int a=min(n,m);
        int b=max(n,m);
        double k=(double)b-a;
        int term=(int)(k*(1+sqrt(5))/2);
        if(term==a)
            printf("0\n");
        else
            printf("1\n");
    }
    return 0;
}


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