来看一道模板题
acwing 884.走迷宫给定一个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 50100001010000000111000010输出样例:8
#include<iostream>
#include<cstring> // memset
#include<queue>
using namespace std;
int n,m;
int Map[110][110];
int From[110][110];
queue<pair<int,int>>q; // 使用队列维护
void bfs(int a,int b)
{
q.push({a,b});
while(!q.empty()) // 队列不空,即还有可以走的点
{
pair<int,int>Start =q.front();
q.pop(); // 读取这个数的值,并弹出队列
Map[Start.first][Start.second]=1; // 表示已经用过
// 上 (0,-1) 下 (0,1) 左 (-1,0) 右 (1,0)
int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};
// 不使用这种方法也可以进行四次判断
for(int i=0;i<4;i++)
{
int x=Start.first+dx[i];
int y=Start.second+dy[i];
// [x][y] 为走过的点
if(Map[x][y]==0)
{
Map[x][y]=1;
From[x][y]=From[Start.first][Start.second]+1; // 更新距离
q.push({x,y});
}
}
}
cout<<From[n][m];
}
int main()
{
memset(Map,1,sizeof(Map)); // 这里将迷宫四周初始化为墙,省去越界判断
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>Map[i][j];
}
}
bfs(1,1);
return 0;
}
整体思路:
从起点开始宽搜遍历地图,当地图遍历完,就求出了起点到终点的距离.
借用一下大佬的图Orz
一些刚开始不懂的点:
1.函数体中使用两个数组存储了四次移动的改变量,dx存储四种移动的横向变化,dy存储纵向的变化.
这种方法代替了四次判断,即:
void bfs(int a,int b)
{
q.push({a,b});
while(!q.empty()) // 队列不空,即还有可以走的点
{
pair<int,int>Start =q.front();
q.pop(); // 读取这个数的值,并弹出队列
Map[Start.first][Start.second]=1; // 表示已经用过
// 进行四次判断
int x=Start.first;
int y=Start.second;
if(Map[x][y+1]==0) // 下
{
Map[x][y+1]=1;
From[x][y+1]=From[Start.first][Start.second]+1;
q.push({x,y+1});
}
if(Map[x][y-1]==0) // 上
{
Map[x][y-1]=1;
From[x][y-1]=From[Start.first][Start.second]+1;
q.push({x,y-1});
}
if(Map[x-1][y]==0) // 左
{
Map[x-1][y]=1;
From[x-1][y]=From[Start.first][Start.second]+1;
q.push({x-1,y});
}
if (Map[x+1][y]==0) // 右
{
Map[x+1][y]=1;
From[x+1][y]=From[Start.first][Start.second]+1 ;
q.push({x+1,y});
}
}
cout<<From[n][m];
}
2.使用memset将迷宫越界的部分化为1(也就是墙),省去了越界判断这一步,否则需要在判断时加上此人在迷宫内这一条件。
memset(*数组名q,数值x,个数n) 通俗来讲时: 将q中n个数变为x;
3.关于循环队列queue
声明:
queue<int>q; queue<pair<int,int>>q;
使用:
push 从队尾插入 pop 从队头弹出 front 返回队头元素
back 返回队尾元素 empty 是否为空 size 长度
4.pair是STL中的模板类型,可以存储两个元素,被称为对组,是二元结构体的替代品,相当于:
struct pair{
typename1 first;
typename2 second;
}
这对值可以有不同的数据类型(T1,T2),两个值可以分别用first和second访问(点操作符)。