Life Winner Bo (博弈)

题目

Bo is a "Life Winner".He likes playing chessboard games with his girlfriend G. 

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

For each game,Bo and G take turns moving a chesspiece(Bo first).At first,the chesspiece is located at (1,1)(1,1).And the winner is the person who first moves the chesspiece to (N,M)(N,M).At one point,if the chess can't be moved and it isn't located at (N,M)(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)(x,y),it can be moved to the next point (x′,y′)(x′,y′) only if x′≥xx′≥x and y′≥yy′≥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 TT as a case number. 

In the next TT lines,there are three numbers type,NN and MM. 

"type" means the kind of the chess. 

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

Output

For each question,print the answer.

翻译

题解

这道题是一些博弈类型的结合,同时也可以用到SG函数做这道题

我们还是要分类讨论:

首先对于王的情况

不管,先用SG函数试一试:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int t;
int n , m;
int ans[1003][1003] = { };
int main(){
    scanf( "%d%d" , &n , &m );
    ans[n][m] = 0;
    for( int i = n ; i >= 1 ; i -- ){
        for( int j = m ; j >= 1 ; j -- ){
            bool f[1003] = {};
            if( j < m )
                f[ans[i][j+1]] = 1;
            if( i < n )
                f[ans[i+1][j]] = 1;
            if( i < n && j < m )
                f[ans[i+1][j+1]] = 1;
            for( int k = 0 ; k <= 1000 ; k ++ ){
                if( f[k] == 0 ){
                    ans[i][j] = k;
                    break;
                }
            }
        }
    }
    for( int i = 1; i <= n ; i ++ ){
        for( int j = 1; j <= m ; j ++ ){
            if( !ans[i][j] ){
                printf( "%d %d\n" , i , j );
            }
        }
    }
}

然后会发现,如果n与m同时为偶的时候就为后手必赢

同时,还有可以理论分析

如果n与m同为偶

那么对于先手的人来说,后手可以模仿他做的步骤,那么就可以维持n与m仍为偶,最后0 0 一定在先手上

比如

4 2 

先手: 3 1

后手: 2 0

先手: 1 0

后手:0 0

只不过想到都为偶数很难

————————————————————————————————————————————————————————

然后就是车的情况,我们也可以用SG函数进行操作

然后发现只有n == m 时,先手必败

当然,可以转化一下题意:

有两堆石子,个数为n , m 每个人至少从一堆中取出一个,求谁胜?

那么这道题就是Nim模型了,可以戳这里(此为转载,内容太多不敢写)

————————————————————————————————————————————————————————

接着是马的情况,也是唯一有平局出现的情况

首先,可以发现,如果n=m且n为3的倍数时,一定是先手必输。

所以设n =k_{1} * 3 + x , m = k_{2} * 3 + y

如果x = 1 , y = 2 或 x = 2 , y = 1时,先手必赢(SG转化)

那么对于其它的情况,由于两方都不想对方赢,所以就会变成平局

————————————————————————————————————————————————————————

对于后的情况,也可以转化一下

有两堆石子n , m可以选择一堆至少选一个,也可以两堆都选至少选一个

那么就是威佐夫博弈

这里谈一下:这里

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int t;
int n , m;
int main()
{
    scanf( "%d" , &t );
    while( t -- ){
        int p;
        scanf( "%d" , &p );
        scanf( "%d%d" , &n , &m );
        if( p == 1 ){
            n --;m --;
            if( n % 2 == 0  && m % 2 == 0  ){
                printf( "G\n" );
            }
            else
                printf( "B\n" );
            continue;
        }
        if( p == 2 ){
            n --;
            m --;
            if( n == m  )
                printf( "G\n" );
            else
                printf( "B\n" );
        }
        else if( p == 3 ){
            n --;m --;
            int k = n / 3 , k1 = m / 3;
            if( n % 3 == 0 && m % 3 == 0 && n == m ){
                printf( "G\n" );
            }
            else if( k == k1 && ( (n % 3 == 1 && m % 3 == 2 ) || ( n % 3 == 2 && m % 3 == 1 ) ) ) {
                printf( "B\n" );
            }
            else
                printf( "D\n" );
        }
        else{
            double temp = ( sqrt( 5.0) + 1.0 ) / 2.0;
            n --;m --;
            double n11 = n , m11 = m;
            double n1 = min( n11 , m11 );
            double m1 = max( n11 , m11 );
            n = min( n , m );
            if( (int)(( m1 - n1 ) * temp) == n ){
                printf( "G\n" );
            }
            else
                printf( "B\n" );
        }
    }
    return 0;
}
发布了68 篇原创文章 · 获赞 7 · 访问量 3845

猜你喜欢

转载自blog.csdn.net/weixin_43823476/article/details/99832851