题目链接
题目描述
在一个 的迷宫中,机器人需要从起点 's' 走到终点 'e'。迷宫中 '.' 代表可通行的路径,'#' 代表障碍物。求机器人到达终点所需的最少步数。如果无法到达,则输出 -1。
解题思路
这是一个典型的在网格图中求解最短路径的问题。由于每一步的成本(权重)都相等(都为1),因此最适合使用广度优先搜索(Breadth-First Search, BFS) 算法。
BFS 的核心思想是从起点开始,像水波纹一样,一层一层地向外探索。它首先访问所有距离起点为 1 的节点,然后是所有距离为 2 的节点,以此类推。这个特性保证了当 BFS 第一次到达终点时,所经过的路径必然是最短的。
算法步骤如下:
-
初始化:
- 创建一个队列,用于存放待访问的格子。队列中每个元素需要存储格子的坐标
(row, col)
和到达该格子的步数steps
。 - 创建一个二维的
visited
数组,用于记录已经访问过的格子,防止重复访问和陷入死循环。 - 遍历迷宫,找到起点 's' 的坐标,并将其作为第一个元素
(start_row, start_col, 0)
加入队列,同时在visited
数组中标记为已访问。
- 创建一个队列,用于存放待访问的格子。队列中每个元素需要存储格子的坐标
-
BFS 循环:
- 当队列不为空时,从队列头部取出一个格子
(r, c, s)
。 - 如果这个格子是终点 'e',则
s
就是最短步数,搜索结束。 - 否则,检查该格子的上、下、左、右四个相邻格子。
- 对于每个满足条件(在边界内、不是墙、未被访问过)的相邻格子,将其加入队列,并更新
visited
数组。新加入队列的格子的步数为s + 1
。
- 当队列不为空时,从队列头部取出一个格子
-
处理无解:
- 如果队列为空时,仍未找到终点,则说明从起点无法到达终点,应输出 -1。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n, m;
cin >> n >> m;
vector<string> maze(n);
int start_r, start_c;
for (int i = 0; i < n; ++i) {
cin >> maze[i];
for (int j = 0; j < m; ++j) {
if (maze[i][j] == 's') {
start_r = i;
start_c = j;
}
}
}
queue<tuple<int, int, int>> q;
q.emplace(start_r, start_c, 0);
vector<vector<bool>> visited(n, vector<bool>(m, false));
visited[start_r][start_c] = true;
int dr[] = {-1, 1, 0, 0};
int dc[] = {0, 0, -1, 1};
while (!q.empty()) {
auto [r, c, steps] = q.front();
q.pop();
if (maze[r][c] == 'e') {
cout << steps << endl;
return 0;
}
for (int i = 0; i < 4; ++i) {
int nr = r + dr[i];
int nc = c + dc[i];
if (nr >= 0 && nr < n && nc >= 0 && nc < m && !visited[nr][nc] && maze[nr][nc] != '#') {
visited[nr][nc] = true;
q.emplace(nr, nc, steps + 1);
}
}
}
cout << -1 << endl;
return 0;
}
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
char[][] maze = new char[n][m];
int startR = -1, startC = -1;
for (int i = 0; i < n; i++) {
maze[i] = sc.next().toCharArray();
for (int j = 0; j < m; j++) {
if (maze[i][j] == 's') {
startR = i;
startC = j;
}
}
}
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{startR, startC, 0});
boolean[][] visited = new boolean[n][m];
visited[startR][startC] = true;
int[] dr = {-1, 1, 0, 0};
int[] dc = {0, 0, -1, 1};
while (!queue.isEmpty()) {
int[] current = queue.poll();
int r = current[0];
int c = current[1];
int steps = current[2];
if (maze[r][c] == 'e') {
System.out.println(steps);
return;
}
for (int i = 0; i < 4; i++) {
int nr = r + dr[i];
int nc = c + dc[i];
if (nr >= 0 && nr < n && nc >= 0 && nc < m && !visited[nr][nc] && maze[nr][nc] != '#') {
visited[nr][nc] = true;
queue.add(new int[]{nr, nc, steps + 1});
}
}
}
System.out.println(-1);
}
}
import sys
from collections import deque
def solve():
n, m = map(int, sys.stdin.readline().split())
maze = [sys.stdin.readline().strip() for _ in range(n)]
start_pos = None
for r in range(n):
for c in range(m):
if maze[r][c] == 's':
start_pos = (r, c)
break
if start_pos:
break
queue = deque([(start_pos[0], start_pos[1], 0)])
visited = [[False for _ in range(m)] for _ in range(n)]
visited[start_pos[0]][start_pos[1]] = True
dr = [-1, 1, 0, 0]
dc = [0, 0, -1, 1]
while queue:
r, c, steps = queue.popleft()
if maze[r][c] == 'e':
print(steps)
return
for i in range(4):
nr, nc = r + dr[i], c + dc[i]
if 0 <= nr < n and 0 <= nc < m and not visited[nr][nc] and maze[nr][nc] != '#':
visited[nr][nc] = True
queue.append((nr, nc, steps + 1))
print(-1)
solve()
算法及复杂度
- 算法:广度优先搜索 (BFS)
- 时间复杂度:
,其中
和
是迷宫的行数和列数。每个格子最多被访问一次。
- 空间复杂度:
,主要用于存储
visited
数组和队列。在最坏的情况下,队列可能需要存储所有可通行的格子。