马的遍历——搜索(bfs/dfs)

题目描述

有一个n*m的棋盘(1<n,m<=400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步

输入格式

一行四个数据,棋盘的大小和马的坐标

输出格式

一个n*m的矩阵,代表马到达某个点最少要走几步(左对齐,宽5格,不能到达则输出-1)

输入输出样例

输入
3 3 1 1
输出
0 3 2
3 -1 1
2 1 4

题意:

在一个二维数组中,马到每一个坐标所需要的步数是多少,若无法到达,则为-1。

题解:

首先要确定马可以走8个方向(根据马走“日”来确定),然后就用搜索的方法,这里讲解两种方法:BFS和DFS。

在这里插入图片描述
根据这个图的逻辑来写出代码

BFS的AC代码

#include<bits/stdc++.h>
using namespace std;
int n, m, sx, sy; //sx,xy为初始马的坐标
int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
int dy[8] = {2, -2, 2, -2, 1, -1, 1, -1}; //dx,,dy是马能走的8个方向
int ans[500][500]; //计步数
bool vis[500][500];  //做标记
int xx, yy; //新的马的坐标

struct xy
{
	int x, y;
}node, top;

queue<xy> q;

void bfs(int x, int y, int step)
{
	ans[x][y] = step;
	vis[x][y] = false;
	node.x = x;
	node.y = y;
	q.push(node);  //将起点放入队列
	while(!q.empty())
	{
		top = q.front();  //取出队列
		q.pop();
		for(int i = 0; i < 8; i++)
		{
			xx = top.x + dx[i];  //新的坐标
			yy = top.y + dy[i];
			if(xx > 0 && xx <= n && yy > 0 && yy <= m)  //判断是否在边界范围内
			{
				if(vis[xx][yy])  //判断是否来过
				{
					node.x = xx;
					node.y = yy;
					q.push(node);   //把新的坐标放入队列
					ans[xx][yy] = ans[top.x][top.y] + 1;  //记录到达的步数
					vis[xx][yy] = false;  //标记来过
				}
			}
		}
	}
}
int main()
{
	cin>>n>>m>>sx>>sy;
	memset(ans, -1, sizeof(ans));
	memset(vis, true, sizeof(vis));
	bfs(sx, sy, 0);
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= m; j++)
		{
			printf("%-5d",ans[i][j]);
		}
		cout<<endl;
	}
}

DFS的方法:

在这里插入图片描述】

根据这张图来写AC代码:

#include<bits/stdc++.h>
using namespace std;
int n, m;
int sx, sy;
int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2};
int dy[8] = {2, -2, 2, -2, 1, -1, 1, -1};
int ans[500][500];  //计步数
int xx, yy;			//新的坐标
void dfs(int x, int y, int step)
{
	ans[x][y] = step;
	if(step > 400)  		//简单的剪枝,因为题目给出1<n,m<=400,
		return ;			//所以如果马从(1,1)到(400,400)
							//最多也不超过400
							//(就看每次x或y走一格,一直走到400格)
	for(int i = 0; i < 8; i++)
	{
		xx = dx[i] + x;
		yy = dy[i] + y;  //新的坐标
		if(xx > 0 && xx <= n && yy > 0 && yy <= m)   //判断是否在边界内
		{
			if(ans[xx][yy] == -1 || ans[xx][yy] > step + 1)
			{  /*第一个是判断是否来过该坐标,第二个是判断如果这个坐标又来到了,
			那与之前的步数相比,是否这次的步数要少,若少,则取这次的步数;反之,则不取*/
				dfs(xx, yy, step + 1);  //这里就不需要进行回溯操作了
			}
		}
	}
}

int main()
{
	memset(ans, -1, sizeof(ans));
	while(cin>>n>>m>>sx>>sy)
	{
		dfs(sx, sy, 0);
		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= m; j++)
			{
				printf("%-5d",ans[i][j]);
			}
			cout<<endl;
		}
	}
}

总结一下

bfs和dfs的最大区别是,dfs是一条路走到底,不撞南墙不回头;而bfs则是一层一层的搜。dfs主要的实现方法就是递归;bfs则是用队列来实现。写题时,需准确的判断是使用那种解题方法,因为对于不同的题,这两种的运行时间是不同的,而这可能也是题目过不了的原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值