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

来源:互联网 发布:ltp1端口 编辑:程序博客网 时间:2024/05/21 17:50

题意

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

思路

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

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

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

  3. knight(骑士/马)
    可以发现能够平局的只有这种情况。
    走法:右12 或 右21
    首先,对于4×4的情况先手方是必败的,实际上,能够必败的也就只有这类情况,即(n=m(n1)0(mod3))。即无论先手方怎么走(只有两种走法),后手都可以走回先手必败的局面。
    必胜的情况,就是在必败的情况之上,加上先手能走的一步,即(n÷3=m÷3n%3m%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
原创粉丝点击