2016 Multi-University Training Contest 3 1003 Life Winner Bo (博弈)

题目链接:HDU5754

简单题意

给出一个n*m的棋盘,一开始有一个棋子在(1,1),两人交替移动棋子,棋子有王,后,马,车四种,移动只能往右下方的子棋盘移动,移动方式按棋子类型有所不同,问谁胜谁负还是平局。

附:国际象棋规则

思路

简单分析一下就可以知道除了马,剩下的三种情况都是必有胜负的,所以可以求一下三种情况下棋盘的SG表,但是直接在程序中动态的打表明显是不现实的,时间复杂度接受不了,但是在本地把SG表打出来以后,一眼就看出了车和王的规律:
车的后手必胜点是只在对角线上,而王的后手必胜点是在横纵坐标都为偶数的点上
这样就省略了两张表,然后仔细观察王后的SG表,发现这个表中零的位置也是有规律的,如下表所示

当前数字是否访问过cnt(增量)最终坐标操作
00(0,0)(0,0+cnt),cnt++
11(1,2)(1,1+cnt),cnt++
22(2,1)none
32(3,5)(3,3+cnt),cnt++
43(4,7)(4,4+cnt),cnt++
54(5,3)none
64(6,10)(6,6+cnt),cnt++
75(7,4)none
85(8,13)(8,8+cnt),cnt++
96(9,15)(9,9+cnt),cnt++

规律就是从0开始遍历,增量初始化为0,如果当前数字已经已经访问过了,坐标就是之前形成的坐标倒过来,继续下一个数字,否则就在当前数字的基础上加上增量,形成另一个数,构成坐标,并把增量加一。

按照这个规律可以O(n)的跑一张SG表中零位置的表出来,然后对输入查表就好了。

很显然,坐标是对称的,所以只用记录一个就行了,我这里记录的是x<y的情况。到时候处理一下输入就行了。

最后是有点麻烦的马,手动推算一下,发现大部分情况下,必败方都能把局面拖向平局,反而能胜利的局面较少,仔细推一下就发现,先手必胜是在对角线两侧,后手必胜是恰好在对角线上,这里的对角线指的是按马的走法形成的对角线,所以要做一个模3的操作,和王后一样,可以把对称的情况在输入上预处理统一一下,简化一下编码。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+10;
bool qu[maxn]={0};
int queu[maxn];

int main(){

    int cnt = 0;
    for(int i = 0 ; i < 1010 ; i ++){
        if(qu[i] == false) {
            queu[i] = i + cnt;
            qu[i+cnt] = true;
            cnt ++;
        }
    }

    int T;
    scanf("%d", &T);
    while(T --){
        int ty,n,m;
        bool flag = false;
        scanf("%d %d %d",&ty, &n,&m);
        n--;m--;
        if(ty == 1) if(n%2 == 0 && m%2 == 0) flag = true;
        if(ty == 2) if(n == m) flag = true;
        if(ty == 3){
            if(n > m) swap(n, m);
            if(n == m && n % 3 == 0) flag = true;
            else if(n % 3 == 1 && m - n == 1) flag = false;
            else {puts("D");continue;}
        }
        if(ty == 4){
            if(n > m) swap(n,m);
            if(queu[n] == m) flag = true;
        }
        if(flag)puts("G");
        else puts("B");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值