题目来源
挑战程序设计竞赛(第二版)
语言
C/C++
题目
迷宫的最短路径
描述
给定一个大小为 N * M 的迷宫。迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格的通道移动。请求出从起点到终点所需要的最小步数。请注意,本题假定从起点一定可以移动到终点。
样例
输入:
N=10,M=10(迷宫如下所示。'#', '.', 'S', 'G' 分别表示墙壁、通道、起点和终点)
# S # # # # # # . #
. . . . . . # . . #
. # . # # . # # . #
. # . . . . . . . .
# # . # # . # # # #. . . . # . . . . #
. # # # # # # # . #
. . . . # . . . . .
. # # # # . # # # .. . . . # . . . G #
输出:
22
思路
该题求最短路径,一般求最短路径、最少操作之类的题都应该想到宽度优先搜索(BFS),因为宽度优先搜索每次对当前结点所有可能达到的位置都遍历一遍,很符合最少的思想。尝试了一下宽度优先搜索,发现果然可以,宽度优先搜索的实现用到了队列的思想。
设置一个二维数组表示距离,用来记录每一步能到达的位置,用无穷大将数组初始化,代表刚开始所有的位置都无法到达。开始时将起点距离设置为 0,进行宽度优先搜索,最后检查终点位置的数值,若为无穷大则不能到达,否则该值为起点到终点的最短距离。
代码
#include <iostream>
#include <queue>
#define MAX_N 100
#define MAX_M 100
using namespace std;
const int INF = 1000000; // 无穷大
// input
char maze[MAX_N][MAX_M] = {
"#S######.#",
"......#..#",
".#.##.##.#",
".#........",
"##.##.####",
"....#....#",
".#######.#",
"....#.....",
".####.###.",
"....#...G#",
};
int M = 10, N = 10;
int sx = 0, sy = 1; // 起点坐标
int gx = 9, gy = 8; // 终点坐标
// input end
// code
struct point{ // 坐标
int x;
int y;
};
int d[MAX_N][MAX_M]; // 到各个位置的最短距离的数组
int dx[4] = {1, 0, -1, 0}; // 下、右、上、左
int dy[4] = {0, 1, 0, -1};
int bfs();
int main() {
int len = bfs();
cout << len << endl;
return 0;
}
// 求从 <sx, sy> 到 <gx, gy> 的最短距离
// 如果无法到达,则是 INF
int bfs()
{
queue<point> que;
// 把所有位置都初始化为 INF
for (int i = 0; i < N; i++){
for (int j = 0; j < M; j++){
d[i][j] = INF;
}
}
// 把起点加入队列,并把这一地点的距离设置为 0
point p;
p.x = sx;
p.y = sy;
que.push(p);
d[sx][sy] = 0;
// 不断循环直到队列长度为 0
while (que.size()){
// 从队列前端取出元素
point p_tem = que.front();
que.pop();
// 如果取出的状态已经是终点,则结束搜索
if (p_tem.x == gx && p_tem.y == gy)
break;
// 四个方向循环
for (int i = 0; i < 4; i++){
// 移动之后的位置记为 <nx, ny>
int nx = p_tem.x + dx[i];
int ny = p_tem.y + dy[i];
// 判断是否可以移动以及是否已经访问过(d[nx][ny] != INF 即为访问过)
if (maze[nx][ny] != '#' && nx >= 0 && nx < N
&& ny >= 0 && ny < M && d[nx][ny] == INF){
// 可以移动的话,则加入队列,并且到该位置的距离确定为到 p 的
// 距离 +1
point p_add;
p_add.x = nx;
p_add.y = ny;
que.push(p_add);
d[nx][ny] = d[p_tem.x][p_tem.y] + 1;
}
}
}
return d[gx][gy];
}
时间复杂度0
最坏情况对整个 N * M 的数组遍历一次,因此时间复杂度为 O(N * M)。
所涉及的知识点
宽度优先搜索(BFS)