马的遍历(题解)
此题为广搜模板题,但有一些变形
我在题解里面翻了一会,并没有找到特别好理解的方法
在此发一篇简单、易懂的题解
也是写一下自己对广度优先搜索的理解
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;
}

浙公网安备 33010602011771号