分析:
本题实质上为给定起点和终点的最短路问题,可以使用宽度优先搜索来解决(Breadth-First Search, BFS 算法虽然可以求解最短路径问题,但是需要注意的是该算法只能求解非带权图的单源最短路径问题,或者说带权值相同且为1的图单源最短路径问题)。当走遍从起点到终点的所有路线时,走过的轨迹会形成一个以起点为根节点的树,此时终点结点的深度就是起点到结点的最短距离。
在下图中,为什么根节点的右孩子先被遍历到了呢?这是与实现相关的
int bfs()
{
...
// dx, dy 数组为 ↑、→、↓、← 方向的 x 轴和 y 轴的偏移量
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
...
// 0、1、2、3 ==== ↑、→、↓、←
for (int i = 0; i < 4; i ++)
...
}
可以看到,我们是按照上右下左的动作顺序来走迷宫的,因此根节点的右孩子会先被遍历到。
代码(C++)
#include <iostream>
using namespace std;
const int N = 110;
typedef pair<int, int> PII;
int n, m;
int maze[N][N];
// dis[][] 数组存储从起点到位置(i,j)的最短距离
int dis[N][N];
PII que[N * N];
int bfs()
{
// 初始化对头指针和队尾指针;队列:队尾进对头出,即先进先出
int head = 0, tail = 0;
// 初始时放入队列的{0,0}作为起点,即左上角
que[0] = {0, 0};
// 初始化 dis数组全为 -1,表示每个位置都没有走过
for (int i = 0; i < n; i ++)
for (int j = 0; j < m; j ++)
dis[i][j] = -1;
// 初始时,“踏”在起点上,距离起点的距离为 0
dis[0][0] = 0;
// dx, dy 数组为 ↑、→、↓、← 方向的 x 轴和 y 轴的偏移量
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
while (head <= tail)
{
// 取对头元素作为当前到达的位置
PII t = que[head ++];
// 将当前的位置结构出来
int nowx = t.first, nowy = t.second;
// 0、1、2、3 ==== ↑、→、↓、←
for (int i = 0; i < 4; i ++)
{
// x, y 为下一个位置
int nextx = nowx + dx[i], nexty = nowy + dy[i];
// 下一个结点是在地图内的合法结点(不是障碍物)且之前没有走到过
if (nextx >= 0 && nextx < n && nexty >= 0 && nexty < m && maze[nextx][nexty] == 0 && dis[nextx][nexty] == -1)
{
// 走到下个位置的距起点的距离比走到当前位置距起点多1
dis[nextx][nexty] = dis[nowx][nowy] + 1;
// 新的位置入队
que[++ tail] = {nextx, nexty};
}
}
}
return dis[n - 1][m - 1];
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i ++)
for (int j = 0; j < m; j ++)
cin >> maze[i][j];
cout << bfs() << endl;
return 0;
}
代码(Python3)
def bfs():
que = []
dis = [[-1] * N for _ in range(N)]
dx, dy = [-1, 0, 1, 0], [0, 1, 0, -1]
dis[0][0] = 0
que.append((0, 0))
# python 中 list 类型的 appen()等于队列的入队,pop(0)等于队列的出队
while que:
nowx, nowy = que.pop(0)
for i in range(4):
nextx, nexty = nowx + dx[i], nowy + dy[i]
if nextx >= 0 and nextx < n and nexty >= 0 and nexty < m and maze[nextx][nexty] == 0 and dis[nextx][nexty] == -1:
dis[nextx][nexty] = dis[nowx][nowy] + 1
que.append((nextx, nexty))
return dis[n - 1][m - 1]
if __name__ == '__main__':
n, m = map(int, input().split())
N = 110
maze = []
for i in range(n):
maze.append(list(map(int, input().split())))
print(bfs())