题目链接 :点击查看
题目描述 :
给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1 表示不可通过的墙壁。
最初,有一个人位于左上角 (1,1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。
数据保证 (1,1) 处和 (n,m) 处的数字为 0 ,且一定至少存在一条通路。
输入输出格式 :
输入
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含 m 个整数(0 或 1),表示完整的二维数组迷宫。
输出
输出一个整数,表示从左上角移动至右下角的最少移动次数。
输入输出样例 :
输入
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来做,但不可以用dfs来做,因为dfs不能保证搜到的路径最短,但是是可以搜索到路径的。实现bfs的核心是队列,对于本题来说,由于是对点进行操作,因此我们将queue定义成pair
但搜索具体要怎么去做呢,广度优先搜索的核心行为是什么?我们知道每个点只能朝4个方向进行移动(不考虑边界点,这里是普遍情况),每一次搜索我们将当前起始点向4个方向移动,判断周围满足条件的点,并将其入队,表明向这个点可以走。移动过程我们可以借助方向数组dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}在for循环中完成从起始点向4个方向的移动。判断条件要考虑是否越界,当前点是否是通路,当前点是否被搜索过这三种情况,要是这三种情况都满足,则对记录距离的数组d进行更新,并将此点入队。总的来说,广度优先搜索的行为核心是从当前点出发对周围点进行试探,试探出满足的点将其入队。在从那个满足条件的点对周围点进行试探,如此循环往复……直到队列内点全部出队。详见如下代码。
代码 :
#include
#include
#include
#include
#include
using namespace std;
typedef pair PII;
const int N = 1e2 + 7;
int d[N][N], g[N][N];//d[x][y]是表示从(0, 0)到(x, y)需要移动的步数
queue q;//队列,储存的是点,为pair类型
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};//表示移动的方向,顺序为左、上、右、下
int main() {
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
cin >> g[i][j];//初始化图阵
memset(d, -1, sizeof(d));//初始距离均为-1除了(0, 0)点 同时也标明此点有没有被用过
q.push({0, 0});//先将(0, 0)点压入队列中
d[0][0] = 0;
while (q.size()) {
auto t = q.front();
q.pop();//取出队头元素 在此可以保证g[t.first][t.second]一定为0, 因为除了(0,0)点,其他点都会经过判断才会入队列
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] == 0 && d[x][y] == -1) {//判断
d[x][y] = d[t.first][t.second] + 1;//更新距离数组
q.push({x, y}); //入队
}
}
}
cout << d[n - 1][m - 1] << endl;//输出(n - 1,m - 1)点到(0, 0)点距离
return 0;
}
-------------------------------------------------------------------------------------------
在此我们给出bfs相关模板
intdir[2][4] = { { 1, 0,-1, 0 }, { 0, 1, 0, -1 } };
status tmp1, tmp2;
tmp1.x = x, tmp1.y = y, tmp1.t = 0;
boolflag = false;
q.push(tmp1); ///< 根节点入队
while(!q.empty()) ///< 检查队列是否为空
{
tmp1 = q.front(); ///< 获取队首元素
q.pop(); ///< 队首元素出队
for(inti = 0; i < 4; i++) ///< 得到队首元素的四个方向状态
{
tmp2 = tmp1, tmp2.x += dir[0][i], tmp2.y += dir[1][i], tmp2.t++;
if(!valid(tmp2)) continue; ///< 若这个坐标不合法
if(is_end(tmp2)) ///< 若坐标是终坐标则输出,并且标记已得到答案
{
flag = true;
output(tmp2);
break;
}
else q.push(tmp2); ///< 新坐标状态入队
}
if(flag) break;
}