2022-11-21 Acwing每日一题

本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的。同时也希望文章能够让你有所收获,与君共勉!

走迷宫

给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1 表示不可通过的墙壁。

最初,有一个人位于左上角 (1,1) 处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。

请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。

数据保证 (1,1) 处和 (n,m) 处的数字为 0,且一定至少存在一条通路。

输入格式
第一行包含两个整数 n 和 m。

接下来 n 行,每行包含 m 个整数(0 或 1),表示完整的二维数组迷宫。

输出格式
输出一个整数,表示从左上角移动至右下角的最少移动次数。

数据范围
1≤n,m≤100
输入样例:
5 5

0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

输出样例:
8

算法原理

BFS的算法原理就是以起始位置作为中心点,以其他距离到起始位置的距离分类,我们先找出距离起始位置距离为1的,再找出距离起始位置距离为2的,不断循环求解,这里需要注意的是,这里搜索时是按照路径中的某一个位置状态去搜索他的四个方向,四个方向的四个位置就对应着四种状态,这就是这道题的状态转移方程,除此之外,BFS是用队列实现的,通用的模板就是只要队列里的元素不为空,那么我们就可以一直搜索,对于每一轮循环,我们先取出队头元素,然后用状态状态转移方程,搜索下一步的状态,判断下一步的状态是否满足要求,如果满足我们就将其存入队列里面。

代码实现

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 105;
typedef pair<int,int> PII;
int g[N][N],d[N][N];    // g表示地图上,d表示每个点距离起始点的距离(层数)
PII q[N*N];
int hh,tt;  // 因为在创建队列就已经加入了一个元素q[0] = {0,0}
int n,m;


int bfs(){
	int dx[4] = {-1,1,0,0},dy[4] = {0,0,-1,1};	// 上下左右,x轴正方向竖直向下,y轴正方向水平向左
	q[0] = {0,0};	// 初始化队列
	memset(d,-1,sizeof d);	// 初始化距离矩阵
	d[0][0] = 0;	// 初始化起始位置
	while(hh <= tt){	// 队列不空说明还有位置没有被搜索过,继续搜索
		PII t = q[hh++];	// 取出一个元素,别忘了 出队的元素头指针要向后移1位
		for(int i=0 ; i < 4 ; ++i){
			int x = t.first + dx[i],y = t.second + dy[i];	// 下一个方向的坐标
			if(x >= 0 && x < n && y >= 0 && y < m && g[x][y] != 1 && d[x][y] == -1){
				q[++tt] = {x,y};	// 如果该位置满足条件就将这个位置放进队列里
				d[x][y] = d[t.first][t.second] + 1;	// 标记这个位置关于原点的距离
			}
		}
	}
	return d[n-1][m-1];	// 根据BFS搜索特性我们可以知道最先标记的距离一定是最短距离
}

int main()
{
    cin >>n >> m;
    for(int i=0; i<n ; ++i)
        for(int j=0; j < m ; ++j)
            cin >> g[i][j];
    cout << bfs() << endl;
    return 0;
}
posted @ 2022-11-21 13:23  ZmQmZa  阅读(15)  评论(0编辑  收藏  举报