URAL 1216 Two Pawns and One King

题意

n*n的棋盘中,有三个国际象棋棋子,分别是黑王,黑兵,白兵。
规定:
如果白兵到底线升变,白方胜
如果黑王被吃,白方胜
如果黑兵到达底线,可以升变。
如果白兵无法移动或被吃,黑方胜。
王、兵移动规则与吃子规则完全模仿国际象棋
问:残局下,谁胜

题解

坑比题。
不计其数的卡,比如王卡象,王卡兵,王卡车,另外还有兵卡王。
注意过路兵这个设定是存在的
比较恶心的在于,白兵可以选择不吃黑兵,直接向前。。。
如果想要少考虑些,可以思考写成DP
但DP也难写,更重要的一点是:白方是具有决策的,而且是有两种:开始走两步以及吃与不吃
剩下的就是一个BFS了

code

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>

typedef long long LL;

const int dxy[8][2] = {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};

const int maxn = 30;

const int maxQ = 6000010;

int n;

struct Point {
    char x, y;
};
struct Node {
    Point wp, bp, bk; bool col;
};

Point wp, bp, bk;
Point _wp, _bp, _bk;

Node Q[maxQ]; int l, r;

bool check(int x, int y) { return 1 <= x && x <= n && 1 <= y && y <= n; }

std::set<LL> inq;
LL encode(const Node& A) {
    return ((((((LL)A.wp.x*30+A.wp.y)*30+A.bp.x)*30+A.bp.y)*30+A.bk.x)*30+A.bk.y)*2 + A.col;
}

void push_Q(const Node& A) {
    int x = encode(A);
    if (inq.count(x)) return;
    inq.insert(x);
    Q[r ++] = A; if (r == maxQ) r = 0;
}

bool white(bool eat, bool fly) {
    l = r = 0; inq.clear();
    push_Q((Node){_wp, _bp, _bk, 0});
    for (; l != r; l = (l+1 == maxQ ? 0 : l+1)) {
        Node u = Q[l]; wp = u.wp, bp = u.bp, bk = u.bk;
//      printf("%d %d %d %d %d %d\n", wp.x, wp.y, bp.x, bp.y, bk.x, bk.y);

        if (u.wp.y == n) continue;

        if (u.col == 0) {
            if (std::abs(bk.x-wp.x) == 1 && bk.y == wp.y + 1) continue;

            if (fly && wp.y == 2) {
                if (!(bp.x == wp.x && bp.y == wp.y+1) && !(bk.x == wp.x && bk.y == wp.y+1)) {
                    if (!(bp.x == wp.x && bp.y == wp.y+2) && !(bk.x == wp.x && bk.y == wp.y+2) && !(std::abs(bp.x-wp.x) == 1 && bp.y == wp.y+2)) {
                        wp.y += 2; push_Q((Node){wp, bp, bk, 1}); wp.y -= 2;
                        continue;
                    }
                } else
                    return 0;
            }
            if (eat && std::abs(bp.x-wp.x) == 1 && bp.y == wp.y + 1) {  push_Q((Node){(Point){bp.x, bp.y}, (Point){-1, -1}, bk, 1}); continue; }

            if (!(bp.x == wp.x && bp.y == wp.y+1) && !(bk.x == wp.x && bk.y == wp.y+1)) {
                ++ wp.y; push_Q((Node){wp, bp, bk, 1}); -- wp.y;
            } else
                return 0;
        } else {
            if (bp.x != -1) {
                if (bp.y == 1) {
                    if (wp.y+1 < n) {  return 0; }
                    if ((wp.x == bp.x+1 && wp.y == bp.y+2) || (wp.x == bp.x+2 && wp.y == bp.y+1) ||
                        (wp.x == bp.x-1 && wp.y == bp.y+2) || (wp.x == bp.x-2 && wp.y == bp.y+1)) { return 0; }

                    if (wp.x == bp.x && !(bk.x == bp.x && bp.y <= bk.y && bk.y <= wp.y))
                        return 0;

                    if (wp.x < bp.x && !(bk.y-bp.y == bp.x-bk.x) && (wp.y <= bp.y + (bp.x-wp.x))) return 0;
                    if (wp.x > bp.y && !(bk.y-bp.y == bk.x-bp.x) && (wp.y <= bp.y + (wp.x-bp.x))) return 0;
                } else {
                    if (std::abs(wp.x-bp.x) == 1 && wp.y == bp.y-1) { return 0; }

                    if (!(wp.x == bp.x && wp.y == bp.y-1) && !(bk.x == bp.x && bk.y == bp.y-1)) {
                        if ((wp.x != bp.x || wp.y != bp.y-2) && bp.y == n-1 && !(std::abs(wp.x-bp.x) == 1 && wp.y == bp.y-2)) { bp.y -= 2; push_Q((Node){wp, bp, bk, 0}); bp.y += 2; }
                        -- bp.y; push_Q((Node){wp, bp, bk, 0}); ++ bp.y;
                    }
                }
            }


            if (std::abs(wp.x-bk.x) <= 1 && std::abs(wp.y-bk.y) <= 1) { return 0; }
            for (int d = 0; d < 8; ++ d) {
                int X = bk.x + dxy[d][0], Y = bk.y + dxy[d][1];
                if (!(bp.x == X && bp.y == Y) && check(X, Y)) { push_Q((Node){wp, bp, (Point){X, Y}, 0}); }
            }
        }
    }
    return 1;
}

void solve() {
    int t1, t2, t3; 
    scanf("%d %c%d %c%d %c%d", &n, &wp.x, &t1, &bp.x, &t2, &bk.x, &t3);
    wp.x -= 'a'-1; bp.x -= 'a'-1; bk.x -= 'a'-1;
    wp.y = t1, bp.y = t2, bk.y = t3;

    _wp = wp; _bp = bp; _bk = bk;

//  printf("%d\n", white(1, 1));
//  printf("%d\n", white(1, 0));
//  printf("%d\n", white(0, 1));
//  printf("%d\n", white(0, 0));

    if (white(1, 1) || white(1, 0) || white(0, 1) || white(0, 0)) puts("WHITE WINS"); else puts("BLACK WINS");
}

int main() {
//  freopen("A.in", "r", stdin);
//  freopen("A.out", "w", stdout);

//  for (int i = 1; i <= 16; ++ i)
    solve();

//  for(;;);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值