2016多校賽 1003(博弈)

Life Winner Bo

Time Limit: 2000/1000 MS (Java/Others)

Problem Description
Bo is a “Life Winner”.He likes playing chessboard games with his girlfriend G.

The size of the chessboard is N×M.The top left corner is numbered(1,1) and the lower right corner is numberd (N,M).

For each game,Bo and G take turns moving a chesspiece(Bo first).At first,the chesspiece is located at (1,1).And the winner is the person who first moves the chesspiece to (N,M).At one point,if the chess can’t be moved and it isn’t located at (N,M),they end in a draw.

In general,the chesspiece can only be moved right or down.Formally,suppose it is located at (x,y),it can be moved to the next point (x′,y′) only if x′≥x and y′≥y.Also it can’t be moved to the outside of chessboard.

Besides,There are four kinds of chess(They have movement rules respectively).

1.king.

2.rook(castle).

3.knight.

4.queen.

(The movement rule is as same as the chess.)

For each type of chess,you should find out that who will win the game if they both play in an optimal strategy.

Print the winner’s name(“B” or “G”) or “D” if nobody wins the game.

Input
In the first line,there is a number T as a case number.

In the next T lines,there are three numbers type,N and M.

“type” means the kind of the chess.

T≤1000,2≤N,M≤1000,1≤type≤4

Output
For each question,print the answer.

Sample Input

4
1 5 5
2 5 5
3 5 5
4 5 5

Sample Output

G
G
D
B

題目大意:

有一個n*m的棋盤,如果能從左上角走到右下角就算贏,B爲先手,G爲後手,有四種棋子,分別是1:國王 2:車 3:馬 4:皇后,(其中皇后我當時推不出來,原來要用到威佐夫博弈)

題目分析:

1003 Life Winner Bo
//這是官方題解:
我們依次分析每一種棋子。

①王。

首先注意一個3*3的棋盤,開始在(1,1),問走到(3,3)誰有必勝策略。

窮舉所有情況,容易發現這是後手贏。

對於NN和MM更大的情況,我們把橫座標每隔3、縱座標每隔3的點都畫出來,這些點都是符合後手勝的。
(因爲無論先手怎麼移動,後手都能重新移動到這些格子,直到到了終點)

如果初始點不在這些點上,就必然是先手勝。因爲先手可以立刻移動到上述的點。

②車。

注意到,如果目前的位置距離終點的xx和yy座標差相等,一定是後手勝。
(因爲先手只能向下或者向右走一段路;無論他往哪裏走,後手往另一維走相同的步數,依然保持這一樣一種狀態。)

反之,先手必然能走到一處相等的位置,轉化爲上述問題,所以一定是先手勝。

③馬。

同樣還是畫圖可以得到規律。

在大多數情況下都是平局。在模3域下,某些地方會存在先後手贏。

④皇后。

畫畫圖後,我們可以將問題轉化爲:

“有兩堆石子,每次可以在一堆裏取任意(非空)顆(相當於是車的走法),或者在兩堆裏取相同(非空)顆(相當於是象的走法),取到最後一顆石子的人獲勝,問先後手誰有必勝策略。”

此題中N\leq 1000N≤1000,可以直接用DP的方法解決。
設f[x][y]爲橫座標距離終點x步,縱座標距離終點y步時,必勝的是先手還是後手。

直接轉移的話,可以枚舉先手的下一步決策進行轉移,這樣是O(N^3)O(N
​3
​​ )的。

注意到轉移只是一行、一列或者斜着一列,這些都可以通過前綴和,做到最終O(N^2)O(N
​2
​​ )。

其實對於更大的NN也是可以做的。

由於敘述起來比較麻煩,具體的結論和證明可以參見:
威佐夫博弈

那麼問題來了,給定一組(a,b)如何判斷它是不是T態,顯然只要找到它是第幾個T態即可,已知公式a[i] = (int)(i*(sqrt(5)+1)/2),b[i] = a[i]+i,那麼就可以通過i = a[i]*(sqrt(5)-1)/2)求出i的值,當然有可能出現精度缺失,所以有可
能算出的i值比實際i值小1,接下來判斷a[i]是否滿足a[i] = (int)(i*(sqrt(5)+1)/2),如果滿足,那麼看b[i]是否滿足b[i]
 = a[i]+i,如果全部滿足說明爲T態,否則爲S態

所以這裏皇后走法等價於威佐夫博弈,
怎麼做呢?

g1=(sqrt(5)+1)/2;
g2=(sqrt(5)-1)/2;(即g1-1

對於(n,m)(不妨假設m>=n)

n=[i*g1];(i=0,1,2,3,4...)
m=n+i;

我們可以先限定住i,用i=int(n*g2)因爲有精度誤差,所以也可能等於i=int(n *g2)+1
然後驗證m是否等於n+i

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+3;
const double gold1=(sqrt(5.)+1)/2.;
const double gold2=gold1-1;
bool vis[maxn];
int sg[maxn],n,m,type,t;

void gett3(int n,int m)
{
   if((m==1&&n==1)||((m-1)%3==0&&(n-1)%3==0))puts("G");
   else
        if((n%3==0&&(m+1)%3==0)||(m%3==0&&(n+1)%3==0))puts("B");
   else
    puts("D");
}

void gett4(int n,int m)
{
    if(n>m)swap(n,m);//n<=m,(n,m)
    int i=n*gold2;
    if(n==int(gold1*i)&&m==n+i||n==int(gold1*(i+1))&&m==n+i+1)puts("B");
    else
        puts("G");
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&type,&n,&m);
        if(type==1)
        {
            if((m&1)&&(n&1))puts("G");
            else
                puts("B");
        }
        else
            if(type==2)
        {
            if(m==n)puts("G");
            else
                puts("B");
        }
        else
            if(type==3)
        {
            gett3(n,m);
        }
        else
            if(type==4)
        {
            gett4(n,m);
        }
    }
    return 0;

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