【数据结构】无穷大棋盘上的马

问题描述:

我们知道,马的走法都是日字。现在假设马在无穷大的棋盘上的(x,y)处,那么下一步它可以走到的点为(x±1,y±2)或(x±2, y±1)。

现在给定初始的马在(0,0)处,马要跳到某个(x_final,y_final)点,而棋盘上有一些凹陷点马无法跳到上面。请求出马跳到(x,y)至少几步并输出答案,如果跳不到请输出fail。

注意每一步就指跳一个日字,而不是移动一格。不考虑中国象棋中的挡马脚规则。

输入:

马要跳到的坐标x_final、y_final

凹陷点数目n

凹陷点坐标

x1 y1

...

xn yn

终点坐标和凹陷点坐标都在(-100, -100)到(100, 100)为对角线的正方形内

输出:

马最少跳的步数

如果跳不到输出fail

样例输入输出:

3 5
4
2 1
1 2
0 3
-1 3

out:

4

这个其实就是一共广度优先遍历,但是不用图来实现,因为太复杂了。棋盘可以看作是一共n^2个顶点的图,每个点和马走的八个方向的点有无向边,起始顶点在(0,0) 。有一些缺陷点,在图中把这些顶点以及相邻的边删除掉就可以了。

可以用一共二维数组记录棋盘,默认是0,走过的即为1,缺陷的记为3;目标点记为2

然后基于广度优先搜索的思想,用一共队列,存目前遍历点八个方向遍历到的点,取出这个点的时候再在八个方向进行搜索。如果前进需要满足2个条件:此点在棋盘内;此点在之前没有遍历过且无凹陷;

代码实现:

#include<iostream>
#include<stdio.h>
#include<queue>

using namespace std;


int cmap[201][201];         //棋盘记录,默认是0,走过的即为1,缺陷的记为3;目标点记为2
int dir[8][2]={{-1,-2},{-2,-1},{-1,2},{-2,1},{1,-2},{2,-1},{1,2},{2,1}};//八个方向

/*
用BFS的方式进行遍历,每个点可以往8个方向前进
如果前进需要满足2个条件:此点在棋盘内;此点在之前没有遍历过且无凹陷(==0);
利用数组储存地图以及行走过的点。
*/
int bfs_horsemove()
{
    queue<int>qrow,qclu,qstep;       //广度优先搜索,辅助队列qxxx,
    qrow.push(100);
    qclu.push(100);
    qstep.push(0);

    while(!qrow.empty())            //每次走完八步,进一次while循环
    {                               //其中,走到未经过点、都会加入下一步队列 qxxx
        int nowrow=qrow.front();
        qrow.pop();
        int nowclu=qclu.front();
        qclu.pop();
        int nowstep=qstep.front();
        qstep.pop();                  
        for(int i=0;i<8;++i){
            int nextrow=nowrow+dir[i][0];
            int nextclu=nowclu+dir[i][1];
            int nextstep=nowstep+1;
            if(nextrow>=0&&nextrow<200&&nextclu>=0&&nextclu<200){
                if(cmap[nextrow][nextclu]==2)     //找到目标,由于是一步一步走的(八个方向循环过一次)
                  return nextstep;                //第一次找到目标,一定是最短路劲 
                if(cmap[nextrow][nextclu]==0){    //在不超过边界且为到过的点、部位凹陷,则进入队列
                    qrow.push(nextrow);
                    qclu.push(nextclu);
                    qstep.push(nextstep);
                    cmap[nextrow][nextclu]=1;
                }
            }
        }
    }
}

int main()
{
    int a,b;
    cin>>a>>b;
    int n;
    cin>>n;
    int umbilic,umbilir;    //缺陷点坐标记录
    for (int i=0;i<n;i++) 
    {
    cin>>umbilir>>umbilic;
    cmap[umbilir+100][umbilic+100]=3;
    }
    cmap[a+100][b+100]=2;

    int ans=bfs_horsemove();
    cout<<ans<<endl;

    cin>>n;
    return 0;
}

这里输入点+100才是原点(0,0),因为点坐标范围都在-100~100,所以棋盘设了201^2个点的大小,现在仔细想想可能是少考虑了一些情况。参考的同学可以把棋盘扩大试试。

算法存在一些没考虑到的点,在OJ中有一个WRONG ANSWER,如果有参考这篇代码把wrong answer解决了的同学,可以私信我或评论一下,感激不尽。

ps:这个代码是jqs老师2021-2022秋季学期数据结构课程OJ作业,如果看到有一样的代码是我本人写的,不是抄袭,老师助教明察。同学们理性参考。

参考博客:

CSDN:BFS 搜索 Problem 1015 Knight Moves "马走日"之最少步数

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值