HNUST 1497 中国象棋中的跳马问题

中国象棋中的跳马问题

首先吐槽一下,oj的报错让我摸不清头脑。
被一个点卡了快两个小时,这也是我写这份题解的原因,希望对你们有用。

在这里插入图片描述

题目描述

题目链接

题目描述:
现在棋盘的大小不一定,由p,q给出,并且在棋盘中将出现障碍物(限制马的行动,与象棋走法相同)

输入描述:
第一行输入n表示有n组测试数据。
每组测试数据第一行输入2个整数p,q,表示棋盘的大小(1<=p,q<=100)。
每组测试数据第二行输入4个整数,表示马的起点位置与终点位置。(位置的取值范围同p,q)
第三行输入m表示图中有多少障碍。
接着跟着m行,表示障碍的坐标。

输出描述:
马从起点走到终点所需的最小步数。
如果马走不到终点,则输入“can not reach!”

输入样例:
2
9 10
1 1 2 3
0
9 10
1 1 2 3
8
1 2
2 2
3 3
3 4
1 4
3 2
2 4
1 3

输出样例:
1
can not reach!

题意

求马从起点(sx,sy)到终点(ex,ey) 最少需要多少步。
如果无法到达则输出"can not reach!"。
要考虑障碍物。

思路

通过 bfs 搜索,如果搜索到了则输出最少需要的步数,如果遍历完了整个图还是没有搜索到,则输出"can not reach!"。更多的细节看代码注释。

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
//开全局变量方便后面dfs调用
int p, q, m;
int sx, sy, ex, ey;//起点(sx,sy),终点(ex,ey)
int a[105][105], b[105][105]; //数组a用来存图,b用来寸最少步数
bitset<105> vis[105]; //用来标记这个点是否
//枚举 8 种跳马的情况
int dx[8] = { 2,1,-1,-2,-2,-1,1,2 };
int dy[8] = { 1,2,2,1,-1,-2,-2,-1 };
//枚举 8 种跳马因障碍物无法移动的情况
int bbx[8] = { 1,0,0,-1,-1,0,0,1 };
int bby[8] = { 0,1,1,0,0,-1,-1,0 };

//判断点(x,y) 是否在棋盘上
int inmap(int x, int y)
{
    if (x >= 1 && x <= p && y >= 1 && y <= q) return 1;
    return 0;
}

//bfs 搜索
void bfs()
{
    queue<pair<int, int>> qe;
    qe.push({ sx,sy });//将起点入队
    while (qe.size())
    {
        //取出队首元素
        int x = qe.front().first, y = qe.front().second;
        qe.pop();
        vis[x][y] = true;
        //如果该点为终点则直接返回
        //也可以不写,因为后面入队的时候就会判一次是不是终点
        if (x == ex && y == ey) return;
        //枚举从点(x,y) 能跳到的8个位置
        for (int i = 0; i < 8; i++)
        {
            int nx, ny;//用来记录将要跳到的点
            nx = x + dx[i];
            ny = y + dy[i];
            int bx, by;//用来阻碍这次移动的障碍物的点
            bx = x + bbx[i];
            by = y + bby[i];
            //首先判断是否在棋盘里面
            //两个 if 也可以合成一个
            if (inmap(nx, ny))
            {
                //如果符合入队的要求则将其入队
                if (!vis[nx][ny] && !a[bx][by] && !a[nx][ny]) 
                {
                    qe.push({ nx,ny });
                    vis[nx][ny] = true;
                    //算最少需要步数,这里可以不用min直接 b[nx][ny] = b[x][y] + 1
                    b[nx][ny] = min(b[nx][ny], b[x][y] + 1);

                    //前面说到的入队这里我们还会判一下,两个位置写哪里都可以
                    if (nx == ex && ny == ey)
                    {
                      vis[nx][ny] = 1;
                      return;
                    }
                }
            }
        }
    }
}
void solve()
{
    //多组数据输入,每次输入数据前要将数据重置,防止之前的数据对本次测试产生干扰
    memset(a, 0, sizeof a);
    memset(b, 0x3f, sizeof b);// b记录最少需要的步数,所以将他赋值为无穷大
    memset(vis, 0, sizeof vis);
    //输入数据
    cin >> p >> q;
    cin >> sx >> sy >> ex >> ey;
    cin >> m;
    b[sx][sy] = 0;// 初始位置的最少步数为 0
    for (int i = 1; i <= m; i++)
    {
        int x, y;
        cin >> x >> y;
        a[x][y] = 1;
        //vis[x][y] = true;
        //这个“vis[x][y] = true;”就是我卡快两个小时的元凶,其实还是自己考虑不周,
        //本意是想直接在输入阶段就把障碍排除,不进行遍历,然后没考虑到终点位置是障碍的情况
        //狂扇自己三大嘴巴子
    }
    //bfs 搜索
    bfs();
    if (vis[ex][ey]) cout << b[ex][ey] << '\n';
    else cout << "can not reach!\n";
    /*if (!vis[ex][ey]||b[ex][ey]>=N) cout << "can not reach!\n"; 
    else cout << b[ex][ey] << '\n';*/
    return;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int _ = 1;
    cin >> _;
    while (_--) solve();
    return 0;
}

ok,到这里就结束了,希望你有所收获,上面的有问题也可以评论或者私信,看到了都会回的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值