马的遍历(题解)

此题为广搜模板题,但有一些变形

我在题解里面翻了一会,并没有找到特别好理解的方法

在此发一篇简单、易懂的题解

也是写一下自己对广度优先搜索的理解

Step1


读入长、宽,和马的初始位置坐标

并将其压入队尾

开始 bfs

Step2


在队列不为空时,一直提取队列中的第一个元素

并进行拓展,将拓展得到的节点压入队尾

重复操作 Step2

Step3


根据数字的长短输出空格即可

代码


注释代码中有,可自行查看

#include<cstdio>
#include<queue>
/*
  <queue> 队列头文件
  用到的函数:
    1:队列名称.front();
      返回队列中的第一个元素
    2:队列名称.pop();
      删除队列中的第一个元素
    3:队列名称.empty();
      检查队列是否为空
        若为空,返回 true
        否则返回 false
    4:队列名称.push(...);
      将括号内元素插入到队列末尾
*/
using namespace std;
queue<int> qx,qy,qstep;
/*
  qx队列用来存放 x 坐标
  qy队列用来存放 y 坐标
  qstep队列用来存放 步数
*/
int n,m,X,Y,a[500][500];
/*
  n 为长, m 为宽
  X,Y代表马从哪里开始跳
  a[][]用来存放最终解
*/
bool vis[500][500];
/*
  vis初始为false
  vis用来判断这个点是否走过
    根据广搜的性质,一个点被第一个搜到一定是最优解
*/
int xx[9]={0,-1,-2,-2,-1,1,2,2,1};
int yy[9]={0,-2,-1,1,2,2,1,-1,-2};
/*
  xx[],yy[]表示马的8种跳法所带来 x 轴和 y 轴的变化
*/
void Print(int x)
{
    int Ws=0;
    if(x==0) printf("    ");//特判,0占一位
    else
    {
        while(x>0)
        {
            ++Ws;// 位数+1
            x/=10;// x/=10 相当于将x的最后一位删除
        }
        for(int S=1;S<=5-Ws;++S)//向左对齐,输出 5-位数 个空格
            printf(" ");
    }
}
void bfs()
{
    int x,y,step;
    while(qx.empty()==0)
    {
        x=qx.front();//返回 qx 第一个元素的值
        y=qy.front();//返回 qy 第一个元素的值
        step=qstep.front();//返回 qstep 第一个元素的值
        a[x][y]=step;
        /*
          广搜的最优性质
        */
        qx.pop();qy.pop();qstep.pop();
        /*
          将 qx,qy,qstep 的第一个元素弹出
        */
        for(int i=1;i<=8;++i)
        {
            if(x+xx[i]>=1 && x+xx[i]<=n && y+yy[i]>=1 && y+yy[i]<=m && vis[x+xx[i]][y+yy[i]]==0)
            /*
              判断是否出界 以及该点是否被访问过
            */
            {
                vis[x+xx[i]][y+yy[i]]=1;//该点被访问
                qx.push(x+xx[i]);//压入新的 x 坐标
                qy.push(y+yy[i]);//压入新的 y 坐标
                qstep.push(step+1);//走到该点又要一步
            }
        }
    }
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&X,&Y);//读入
    qx.push(X);//将初始位置 x 坐标压入队列
    qy.push(Y);//将初始位置 y 坐标压入队列
    qstep.push(0);//初始位置只要走 0 步
    vis[X][Y]=1;//坑点,要将初始位置设为走过,否则会出现回跳现象
    bfs();//将任务交给广搜
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=m;++j)
            if(!vis[i][j]) printf("-1   ");//若该点未走到过,则输出 -1 以及3个空格
            else
            {
                printf("%d",a[i][j]);//输出那个数
                Print(a[i][j]);//输出对应的空格数
            }
        printf("\n");//回车
    }
    return 0;
}
posted @ 2020-08-07 15:01  riced  阅读(438)  评论(0)    收藏  举报