HDU-5754 Life Winner Bo (博弈论)

好久没有整题目了,并不是没有好的题目整,只是自己懒了太懒了太懒了。。。赶紧整理几个题补一下自己的罪过。。。

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的棋盘,一枚棋子要从左上角(0,0)到右下角,两个人轮流移动,谁移动到最后一步谁胜利,移动规则如下,有四种棋子:
1、king 国王     向右,向下,或者向右下移动一格
2、castle 车      向右,或者向下移动任意格
3、knight 马      向2*3的矩阵的另一个角移动
4、queen 王后  移动到同一行、列、斜线的任意位置

思路:

很明显这个是一个博弈的题目。他好在有四种棋子,分别对应四种走法,也就是将四个博弈结合在了一起。

将棋盘看作两堆石子,棋子移动取就是两堆石子,谁先取完谁胜利,一堆石子n-1个,一堆m-1个。

将四种博弈分别分析

1、king 国王     向右,向下,或者向右下移动一格,简化成石子问题就是可以在其中一堆取一个(向右、向下)或者在两堆中各取一个(向右下)。最终取到(0,0)   那就很明显了,最终结果是偶偶的,每一次偶偶都只能变成奇偶,偶奇,奇奇,然而这三种都能一次变成偶偶。于是就有答案了,谁面对偶偶的局势谁就输,对方只要保持每次都让他面对偶偶的局势就能保证取走最后的石子。这是对于n-1和m-1,对于n,m就是当n,m都为奇数时第一个人面对必败态,否则第一个人胜利。

2、castle 车    向右,或者向下移动任意格,简化成石子问题就是从某一堆中取出任意个,简单的nim博弈就能解决。同样也可以理解为一开始就保证和终点在一条对角线上,一定是先手赢,所以必胜策略就是先手移动到对角线上——然而如果一开始就是一个正方形,那先手肯定必败了。

3、knight 马      向2*3的矩阵的另一个角移动, Knight的移动方法跟马一样走日字,它比较难处理,因为它有和局的情况(比如某个人一直往右走,导致对面无路可走)使对手无法获得胜利…这样的情况看似麻烦,其实我们也可以用相同的思想分析必胜和必败状态。 我们先区分能分出胜负的局面和平局的局面,通过画图,我们可以发现(2,3)和(3,2)这样的情况是一定先手必胜的,而想(3,3)这种情况就无法达到,更进一步,我们发现(4,4)这种情况是一定必败的,而其他比它小的情况全部是平局。     更进一步,我们发现(5,6)这种情况也是必胜的:我们只需要先手走到(2,3)这个点就可以,在之前,我们知道(4,4)是先手必败,而在这里,我们如果把(2,3)看作起始点,把(5,6)看作终点,其组成的正方形和刚才那种情况一模一样:这说明这就是一种可以区分胜负的局面,从(4,4)开始,(7,7),(10,10)….均为先手必败,然而我们如果可以先手走到这样一种必败的局面,我们即是必胜的——而其余情况,全为和局。 到这里我们就可以写出最终结果了:当终点减去起点的坐标能被3整除的时候,先手必败;对于必胜条件,我们只需要判断(2,3)和(3,2)是否可以达到必败局面就可以了。

4、queen 王后  移动到同一行、列、斜线的任意位置,简化成石子问题就是可以在一堆中去任意个,也可以在两堆中取相同个。经典的威佐夫博弈问题,我们可以直接求解。

代码:

#include <bits/stdc++.h>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>

#define IO ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

typedef long long LL;
const long long INF = 0x3f3f3f3f;
const long long mod = 1e9+7;
const double PI = acos(-1.0);
const int maxn = 100000;
const char week[7][10]= {"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
const char month[12][10]= {"Janurary","February","March","April","May","June","July",
                           "August","September","October","November","December"
                          };
const int daym[2][13] = {{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
const int dir4[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
const int dir8[8][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, 1}, {-1, -1}, {1, -1}, {-1, 1}};

using namespace std;

int main()
{
    IO;
    int T;
    cin>>T;
    int logo=1;
    while(T--)
    {
        int t,n,m;
        cin>>t>>n>>m;
        n--;
        m--;
        if(t==1)
        {
            if(n%2==0&&m%2==0)
                cout<<"G"<<endl;
            else
                cout<<"B"<<endl;
        }
        if(t==2)
        {
            if(n==m)
                cout<<"G"<<endl;
            else
                cout<<"B"<<endl;
        }
        if(t==3)
        {
            if (n==m&&n%3==0)
                cout<<"G"<<endl;
            else if (n-1==m&&(n-1)%3==1)
                cout<<"B"<<endl;
            else if (n==m-1&&n%3==1)
                cout<<"B"<<endl;
            else
                cout<<"D"<<endl;
        }
        if(t==4)
        {
            int ak=0;
            int a=n;
            int b=m;
            double k;
            k=(sqrt(5.0)+1.0)/2.0;
            if(a>b)
            {
                t=a;
                a=b;
                b=t;
            }
            t=b-a;
            ak=(int)(t*k);
            if(a==ak)
                cout<<"G"<<endl;
            else
                cout<<"B"<<endl;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/aiguona/p/8360525.html