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


题目来源

P1443 马的遍历


完整代码如下

#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");
	}

相似题目

BFS-迷宫最短路径问题

summary

其实本题也蕴含DP问题的思想我们用刚开始走1步的点的步数去更新2步的点的步数
用前面的数据去更新后面的数据,本身步数的累加便是一个+1+1的更新过程,也蕴含累加的思想

end

以上是关于BFS-马的遍历的主要内容,如果未能解决你的问题,请参考以下文章

BFS-马的遍历

BFS-马的遍历

1443 马的遍历

Luogu1443 马的遍历STL通俗BFS

马的遍历

P1443 马的遍历