HDU 5897 (博弈 模拟 bfs)

9 篇文章 0 订阅
6 篇文章 0 订阅

题目链接:点击这里

题意:Alice有一个帅,Bob有一个将和一个马,Alice要尽可能拖延时间,Bob要尽快获胜,问Bob获胜双方走的步数。如果Alice获胜输出“Luck guy!”。平局视为Alice赢。

(作为出题人之一居然这个小模拟成了最少人过的题QAQ,估计是大家被前面各种错误弄得烦了懒得写了~~)

Alice获胜有两种:1.第一步吃掉Bob的将;2.第一步吃掉Bob的马而不被Bob的将相对,通过平局获胜。
所以直接预处理把这些获胜条件挖出来标记上,然后其他的所有状态判断哪些是Bob的一步必胜态,这些步数都是1,然后将这些状态扔进一个队列bfs。根据博弈的思想,Bob要尽快解决战斗,所以Bob必然走向一个步数最少的状态,而Alice要拖延时间,所以她要走向一个步数最多的状态。所以状态需要记录三个棋子的位置,先手的人以及走到结束的步数。
如果队首状态是Alice先手,说明上一步是Bob先手,枚举能够到达队首状态的所有未知状态(注意判马脚),那么状态下Bob先手获胜步数就是队首状态步数+1。如果队首状态是Bob先手说明上一步是Alice先手,维护下能够到达队首状态的所有状态能够走到的最大步数的值(Alice尽量拖延时间)。
这样一直把所有状态搜完就好了,细节比较多,还是比较恶心的~~

附上标称:

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <time.h>
using namespace std;
#define maxn 105

const int move_ma[8][2] = {///马移动
    {-2, -1}, {-2, 1}, {-1, -2}, {1, -2},
    {-1, 2}, {1, 2}, {2, -1}, {2, 1}
};
const int no[4][2] = {///马脚
    {-1, 0}, {0, -1}, {0, 1}, {1, 0}
};
const int move_shuai[4][2] = {///将移动
    {1, 0}, {-1, 0}, {0, 1}, {0, -1}
};
int Max[maxn][10][10], cnt[maxn][10][10];
int vis[maxn][10][10][2];
///敌马的位置 敌将位置 我将位置 0:我先手 1:敌先手
///状态下的失败步数
///0表示我必胜
int out[maxn][10][10];
///我先走 这个状态后继状态中有多少种合法状态

struct node {
    int a, b, c;///马位置 敌将位置 我将位置
    int id;///0:我先手 1:敌先手
    int step;///这个状态下失败的步数
    node (int _a, int _b, int _c, int _id, int _s) {
        a = _a, b = _b, c = _c, id = _id, step = _s;
    }
};
queue <node> q;

bool balk (int now, int next, int i, int j) {
    int x = now/9, y = now%9;
    int xx = next/9, yy = next%9;
    //cout << x << " " << y << endl;
    //cout << xx << " " << yy << endl;
    for (int k = 0; k < 8; k++) { 
        if (xx == x+move_ma[k][0] && yy == y+move_ma[k][1]) { //cout << k << endl;
            int xxx = x+no[k/2][0], yyy = y+no[k/2][1];
            //cout << xxx << " " << yyy << endl;
            if (xxx == i/3+7 && yyy == i%3+3) return 1;
            if (xxx == j/3 && yyy == j%3+3) return 1;
        }
    }
    return 0;
}

void bfs () {
    while (!q.empty ()) {
        node now = q.front (); q.pop ();
        int x = now.c/3, y = now.c%3;///我帅
        int ma_x = now.a/9, ma_y = now.a%9;///敌马
        if (now.id == 0) {///这一步是我先手 上一步是敌先手
            for (int i = 0; i < 4; i++) {///敌走将
                int xx = now.b/3+move_shuai[i][0], yy = now.b%3+move_shuai[i][1];///上一步敌将的位置
                if (xx < 0 || xx >= 3 || yy < 0 || yy >= 3) continue;
                if (vis[now.a][xx*3+yy][now.c][1] != -1) continue;
                if (xx+7 == ma_x && yy+3 == ma_y) continue;///敌将和马不重合
                vis[now.a][xx*3+yy][now.c][1] = now.step+1;
                q.push (node (now.a, xx*3+yy, now.c, 1, now.step+1));
            }

            for (int i = 0; i < 8; i++) {
                int xx = ma_x+move_ma[i][0], yy = ma_y+move_ma[i][1];
                if (xx < 0 || xx >= 10 || yy < 0 || yy >= 9) continue;
                if (vis[xx*9+yy][now.b][now.c][1] != -1) continue;
                if (xx == now.b/3+7 && yy == now.b%3+3) continue;///敌将和马不重合
                if (xx == x && yy == y+3) continue;///敌马和我帅不重合
                if (balk (xx*9+yy, now.a, now.b, now.c)) continue;///马脚
                vis[xx*9+yy][now.b][now.c][1] = now.step+1;
                q.push (node (xx*9+yy, now.b, now.c, 1, now.step+1));
            }
        }
        else {///上一步是我先手
            for (int i = 0; i < 4; i++) {
                int xx = x+move_shuai[i][0], yy = y+move_shuai[i][1];///上一步我的位置
                if (xx < 0 || xx >= 3 || yy < 0 || yy >= 3) continue;
                if (vis[now.a][now.b][xx*3+yy][0] != -1) continue;
                if (xx == ma_x && yy+3 == ma_y) continue;///上一步不可能重合
                Max[now.a][now.b][xx*3+yy] = max (Max[now.a][now.b][xx*3+yy], now.step);
                if (++cnt[now.a][now.b][xx*3+yy] == out[now.a][now.b][xx*3+yy]) {
                    vis[now.a][now.b][xx*3+yy][0] = Max[now.a][now.b][xx*3+yy]+1;
                    q.push (node (now.a, now.b, xx*3+yy, 0, vis[now.a][now.b][xx*3+yy][0]));
                }
            }
        }
    }
}

int relation (int x, int y, int i, int j, int who) {
    ///0:我必败 1:我必胜 2:不一定
    int x1 = i/3, y1 = i%3;///敌将
    int x2 = j/3, y2 = j%3;///我帅
    y1 += 3, y2 += 3;
    if (y1 == y2) {///两王相对(中间没有马) 胜负立分
        if (y == y1) {
            if (x > x1+7 || x < x2) {
                if (who == 0) return 1;
                return 0;
            }
            else return 2;
        }
        if (who == 0)
            return 1;
        else
            return 0;
    }
    if (who == 1) {
        int d1 = abs (x-x2), d2 = abs (y-y2);
        if ((d1 == 1 && d2 == 2) || (d1 == 2 && d2 == 1))
            return 0;///被敌马吃掉
        return 2;
    }
    ///马被吃
    if (x > 2 || y < 3 || y > 5) return 2;//马在外面
    if (y == y2) {
        if (x2-x == 1) {///在我将的下侧
            return 1;
        }
        if (x-x2 == 1) {///在我将的上侧
            if (y1 == y) return 2;///有敌将的保护
            return 1;
        }
        return 2;
    }
    if (x == x2 && abs (y-y2) == 1 && y <= 5 && y >= 3) {///在我将的左右侧
        if (y1 == y)
            return 2;///有敌方将的保护
        return 1;
    }
    return 2;
}

void init () {
    while (!q.empty ()) q.pop ();
    memset (vis, -1, sizeof vis);
    memset (Max, 0, sizeof Max);
    memset (out, 0, sizeof out);
    memset (cnt, 0, sizeof cnt);
    for (int x = 0; x < 10; x++) for (int y = 0; y < 9; y++) {///敌马位置
        for (int i = 0; i < 9; i++) {///敌将位置
            for (int j = 0; j < 9; j++) {///我将位置
                if ((y-3 == j%3 && x == j/3) || (y-3 == i%3 && x-7 == i/3))
                    continue;///马和将重合
                int res0 = relation (x, y, i, j, 0);
                int res1 = relation (x, y, i, j, 1);
                if (!res0)
                    vis[x*9+y][i][j][0] = 1, q.push (node (x*9+y, i, j, 0, 1));
                else if (res0 == 1) vis[x*9+y][i][j][0] = 0;
                if (!res1)
                    vis[x*9+y][i][j][1] = 1, q.push (node (x*9+y, i, j, 1, 1));
                else if (res1 == 1) vis[x*9+y][i][j][1] = 0;

                for (int k = 0; k < 4; k++) {///我先走
                    int next_x = j/3+move_shuai[k][0], next_y = j%3+move_shuai[k][1];
                    if (next_x < 0 || next_x >= 3 || next_y < 0 || next_y >= 3) continue;
                    if (next_x == x && next_y+3 == y) continue;///和马重合的状态已经计算过了
                    out[x*9+y][i][j]++;
                }
            }
        }
    }
    bfs ();
}

int x, y, xx, yy, xxx, yyy;

int main () {
    //freopen ("in", "r", stdin);
    //freopen ("out", "w", stdout);
    init ();    int t;
    //cout << balk (21, 32, 0, 7) << endl;
    //cout << vis[30][1][6][1] << endl;
    //cout << vis[0][0][0][0] << endl;
    cin >> t;
    int who;
    //输入敌马 敌将 我将坐标 先手的人
    while (t--) {
        cin >> x >> y >> xx >> yy >> xxx >> yyy >> who;
        xx -= 7, yy -= 3;
        yyy -= 3;
        int res = vis[x*9+y][xx*3+yy][xxx*3+yyy][who];
        if (res == 0) {
            cout << "Lucky guy!" << endl;
        }
        else 
            cout << "Lose in " << res << " steps T.T!" << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值