(HDU 5754)2016 Multi-University Training Contest 3 Life Winner Bo (博弈/DP)

题意

在一个 n×m 的棋盘左上角有一个棋子(四种类型之一),要求移动到右下角(只能往右或者往下),问都采取最优策略的情况下,先手方是否必胜(或者平局)。

思路

从来没做过这么奇怪的博弈题,写完就会下国际象棋了。。
我们按棋子的类型分类讨论

  1. king(国王)
    走法:右 1 或下1或右下 1
    当且仅当n m 都为奇数时,先手必败,否则必胜。
    可以枚举3×3的情况,先手必败,对于其他的必败情况,一定可以最终转换到 3×3 的必败情形(这个我没仔细推,可能有点想当然)

  2. rook(车)
    走法:右 n 或下n
    这个一看就是nim博弈有没有,石子有 2 堆嘛。。
    当然因为只有2堆,分类讨论也是可以的,当且仅当 n=m 时必败。

  3. knight(骑士/马)
    可以发现能够平局的只有这种情况。
    走法:右 1 2 或 右 2 1
    首先,对于 4×4 的情况先手方是必败的,实际上,能够必败的也就只有这类情况,即( n=m (n1)0(mod3) )。即无论先手方怎么走(只有两种走法),后手都可以走回先手必败的局面。
    必胜的情况,就是在必败的情况之上,加上先手能走的一步,即( n÷3=m÷3 n%3 m%3 中一个为1,一个为2)
    否则平局。

  4. queen(皇后)
    走法:右n或下n或右下n
    这个是威佐夫博弈的模型,从2堆石子中任选1堆取或者2堆取一样的数目(不能不取)。
    开始的几个必败态为(数字表示能走的步数,即 (n1,m1) ):
    (0,0) (1,2) (3,5) (4,7) 。。
    即第一个数是从来没出现过的最小自然数,第二个数和第一个数的关系为:

    Y=X×(5+1)2

    黄金分割比+1倍有木有。。

代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
#define debug(a) printf("a =: %d\n",a);
const int INF=0x3f3f3f3f;
const int maxn=1e3+50;
const int Mod=1e9+7;
const double PI=acos(-1);
const double d1618=(sqrt(5)+1)/2;
typedef long long ll;
using namespace std;

const int KNIGHT=3;
const int QUEEN=4;
const int KING=1;
const int ROOK=2;
const int WIN=1;
const int DRAW=0;
const int LOSE=-1;

int t,n,m;
int sn,sm;
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
   // initKnight();
    int T; scanf("%d",&T);
    while(T--){
        scanf("%d %d %d",&t,&n,&m);
        sn=n-1;
        sm=m-1;
        int ret,tmp;
        if (t==KNIGHT){
            if (sn==sm && sn%3==0 && sm%3==0) ret=LOSE;
            else {
                int tn=sn%3,tm=sm%3;
                if (tn>tm) swap(tn,tm);
                if (sn/3==sm/3 && tn==1 && tm==2) ret=WIN;
                else ret=DRAW;
            }
        }else if (t==KING){
            if ((n&1) && (m&1)) tmp=0;
            else tmp=1;
            if (tmp==0) ret=LOSE;
            else ret=WIN;
        }else if (t==ROOK){
            tmp=sn^sm;
            if (tmp==0) ret=LOSE;
            else ret=WIN;
        }else if (t==QUEEN){
            if (sn>sm) swap(sn,sm);
            int nn=(sm-sn)*d1618;
            if (nn==sn) ret=LOSE;
            else ret=WIN;
        }
        if (ret==WIN) puts("B");
        else if (ret==LOSE) puts("G");
        else puts("D");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值