威佐夫遊戲 51Nod - 1072 (威佐夫博弈)

有一堆石子共有N個。A B兩個人輪流拿,A先拿。每次最少拿1顆,最多拿K顆,拿到最後1顆石子的人獲勝。假設A B都非常聰明,拿石子的過程中不會出現失誤。給出N和K,問最後誰能贏得比賽。

例如N = 3,K = 2。無論A如何拿,B都可以拿到最後1顆石子。

Input
第1行:一個數T,表示後面用作輸入測試的數的數量。(1 <= T <= 10000) 第2 - T + 1行:每行2個數N,K。中間用空格分隔。(1 <= N,K <= 10^9)
Output
共T行,如果A獲勝輸出A,如果B獲勝輸出B。
Sample Input

4
3 2
4 2
7 3
8 3

Sample Output

B
A
A
B

問題:首先有兩堆石子,博弈雙方每次可以取一堆石子中的任意個,不能不取,或者取兩堆石子中的相同個。先取完者贏。

分析:首先我們根據條件來分析博弈中的奇異局勢

第一個(0 , 0),先手輸,當遊戲某一方面對( 0 , 0)時,他沒有辦法取了,那麼肯定是先手在上一局取完了,那麼輸。

第二個 ( 1 , 2 ),先手輸,先手只有四種取法,

1)取 1 中的一個,那麼後手取第二堆中兩個。

2)取 2 中一個,那麼後手在兩堆中各取一個。

3)在 2 中取兩個,那麼後手在第一堆中取一個。

4)兩堆中各取一個,那麼後手在第二堆中取一個。

可以看出,不論先手怎麼取,後說總是能贏。所以先手必輸!

第三個 ( 3 , 5 ),先手必輸。首先先手必定不能把任意一堆取完,如果取完了很明顯後手取完另一堆先手必輸,那麼

假如看取一堆的情況,假設先手先在第一堆中取。 取 1 個,後手第二堆中取4個,變成(1 ,2)了,上面分析了是先手的必輸局。

取 2 個,後手第二堆中取3個,也變成( 1 , 2)局面了。

假設先手在第二堆中取,取 1 個,那麼後手在兩堆中各取 2 個,也變成 ( 1 , 2 )局面了。

取 2 個 ,那麼後手可以兩堆中都去三個, 變成 ( 0 , 0)局面,上面分析其必輸。

取 3 個,後手兩堆各取 1 個 ,變成( 1 , 2)局面了。

取 4 個,後手在第一堆中取一個,變成( 1 , 2)局面了。

可見不論先手怎麼取,其必輸!

第四個(4 , 7),先手必輸。

自己推理可以發現不論第一次先手如何取,那麼後手總是會變成前面分析過的先手的必輸局面。

那麼到底有沒有什麼規律,我們繼續往下寫。

第四個 ( 6 ,10 )

第五個 ( 8 ,13)

第六個 ( 9 , 15)

第七個 ( 11 ,18)

會發現他們的差值是遞增的,爲 0 , 1 , 2, 3, 4 , 5 , 6, 7…n

而用數學方法分析發現局面中第一個值爲前面局面中沒有出現過的第一個值,比如第三個局面,前面出現了 0 1 2,那麼第三個局面的第一個值爲 3 ,比如第五個局面,前面出現了 0 1 2 3 4 5 ,那麼第五個局面第一個值爲6。

再找規律的話我們會發現,第一個值 = 差值 * 1.618

1.618 = (sqrt(5)+ 1) / 2 。

黃金分割率是0.618,而威佐夫博弈正好是1.618

理論知識不好理解,但是代碼很短,如下:

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
int main()
{
    int n,a,b,s=0;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%d %d",&a,&b);
        if(a>b)
         swap(a,b);   // 交換爲了保證 b-a爲正數
         s=(b-a)*(sqrt(5)+1)/2;    //1.618=sqrt((5)+1)/2;
         if(s==a)
            printf("B\n");
         else
            printf("A\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章