BFS-马的遍历
Posted 桃花涣小鱼干
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BFS-马的遍历相关的知识,希望对你有一定的参考价值。
马的遍历
题目描述
有一个n*m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步
输入格式
一行四个数据,棋盘的大小和马的坐标
输出格式
一个n*m的矩阵,代表马到达某个点最少要走几步(左对齐,宽5格,不能到达则输出-1)
输入样例
3 3 1 1
输出样例
0 3 2
3 -1 1
2 1 4
题目来源
完整代码如下
#include<stdio.h>
#define MAX 170000
struct queue
{
int x;//行坐标
int y;//列坐标
};
struct queue que[MAX];//最多160000个点这里令MAX=170000
int head = 0, tail = 1;//队列引入
int a[401][401];
int n, m, sx, sy;
//定义8组方向,这里的t是try的缩写,表示去试探的方向
int tx[16] = { 2,-2,2,-2,-1,1,-1,1 };
int ty[16] = { 1,1,-1,-1,2,2,-2,-2 };
void init()
{
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
a[i][j] = -1;
a[sx][sy] = 0;
}
int main()
{
scanf("%d%d%d%d", &n, &m, &sx, &sy);
init();//初始化
//队列初始化
que[1].x = sx;
que[1].y = sy;
while (head < tail)
{
head++;
for (int i = 0; i<8; i++)
{
int nx = que[head].x + tx[i];
int ny = que[head].y + ty[i];
if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && a[nx][ny] == -1)
{
tail++;
que[tail].x = nx;
que[tail].y = ny;
a[nx][ny] = a[que[head].x][que[head].y] + 1;
}
}
}
//输出
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
printf("%-5d", a[i][j]);
printf("\\n");
}
return 0;
}
思路详解
(1)这是什么类型的题?
我们要得到的是马到达每一个点的
最小步数
,而BFS恰好是按照最小步数一层层往下拓展的
在其拓展的同时我们可以自然地得到
到达每一个点的最小步数,所以我们可以用BFS
来解决这道题
(2)代码实现
第一步:读入并初始化
scanf("%d%d%d%d", &n, &m, &sx, &sy);//start-x,start-y起点的行坐标和列坐标
init();//初始化
initialize-初始化函数如下:
void init()
{
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
a[i][j] = -1;
a[sx][sy] = 0;
}
问题:为什么要先全令成-1而不是0?
答:因为为0时表示起点到起点需要0步,而不能到达的点需要用 -1 来表示
我们在-1的蓝图上再进行a[sx][sy] = 0 和 BFS 拓展操作 这样再输出时没有被再次赋值的点就是不能到达的点,既符合题目要求,又方便
第二步:引入队列
int head = 0, tail = 1;//队列引入
//队列初始化
que[1].x = sx;
que[1].y = sy;
第三步:BFS的拓展部分(核心代码)
while (head < tail)
头和尾之间差的是
一层的拓展
,一个head可以拓展出多个tail。
只有不能再拓展了(tail不再++
),head到达tail的位置时结束循环
head++;
头指针head去
赶
尾指针tail向前走(往下拓展)
for (int i = 0; i<8; i++)
{
int nx = que[head].x + tx[i];
int ny = que[head].y + ty[i];
if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && a[nx][ny] == -1)
{
tail++;
que[tail].x = nx;
que[tail].y = ny;
a[nx][ny] = a[que[head].x][que[head].y] + 1;
}
}
向八个方向试探,当不越界且未走过时(保证距离最短避免重复走)向下拓展
tail++拓宽队列,将新的点入队,记录步数。
问题:为什么是
a[nx][ny] = a[que[head].x][que[head].y] + 1;
?
答:因为BFS每一次向下试探拓展
,其跨度的大小均为1
(步数)
每一次拓展成功意味着head
位置的点向tail
位置的点跨出一步
我们只需要将原来走的步数
即(a[que[head].x][que[head].y])加1即可
第一次进入while循环时,我们先head++,此时head为1,头指针指向起始位置head位置的点是起始点
,起始点的步数为0已经初始化
过了其向下走一步恰好为0+1=1
,
第四步:输出
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
printf("%-5d", a[i][j]);
printf("\\n");
}
相似题目
summary
其实本题也蕴含DP问题的思想我们用刚开始走1步的点的步数去更新2步的点的步数
用前面的数据去更新后面的数据,本身步数的累加便是一个+1+1的更新过程,也蕴含累加的思想
end
以上是关于BFS-马的遍历的主要内容,如果未能解决你的问题,请参考以下文章