算法-广度优先遍历-判断迷宫是否有出口

题目要求

题目的题目大致如下:判断在一个由 0(通路)和 1(墙壁)组成的二维迷宫中,是否存在一条从起点到终点的有效路径。我只能上下左右移动,不能穿墙,也不能走出迷宫。

一开始的思路

我的第一反应是使用递归。我构思了一个递归函数 bfs(x_now, y_now, ...),它会从当前位置开始,检查相邻的四个方向。如果某个方向是通畅的,我就继续向那个方向递归。如果最终能走到终点,那路径就找到了。

但很快我就发现这个思路不对。虽然我把函数命名为 bfs,但这种递归的实现方式本质上是深度优先搜索(DFS) 。它会沿着一条路走到死胡同才回头,这和迷宫问题中寻找路径的本质------向外"一层层扩散"------并不相符。而且,递归有一个潜在的风险:如果迷宫很大,或者存在很长的路径,递归的深度可能会导致栈溢出,程序会直接崩溃。我意识到,这种方法并不适合这个场景,于是我放弃了这条路线。

使用 deque 改进后的思路

BFS 的核心思想是"一层层"地探索,回顾之前数据结构的知识点后,我记起BFS一般都是用队列这个数据结构来实现的。为确保我能最快地找到所有相邻的、可达的位置。我选择了 collections.deque 来实现这个思路,因为它是一个双端队列,能高效地执行 append(入队)和 popleft(出队)操作,并且这两个操作时间复杂度都是O(1)。

我的具体步骤是:

  1. 创建一个 deque 队列,并将起点坐标 (x_1, y_1) 入队。
  2. 为了避免重复访问同一个位置,我选择直接修改迷宫矩阵,将访问过的通路 0 改为 1
  3. 然后,我进入一个 while 循环,只要队列不为空,就一直进行搜索。
  4. 在循环中,我从队列中取出一个位置 (x, y),然后检查它的上下左右四个邻居。
  5. 如果一个邻居满足三个条件:在迷宫范围内、是通路(值不为 1)、且从未被访问过,我就把这个邻居加入队列。

出现的问题

我按照上述思路实现了代码,但提交后,有一个测试点超时了。这让我很困惑,因为我自认为已经用了正确的 BFS 算法。

出现原因

经过仔细排查,我找到了问题所在:我标记已访问节点的位置不对。

python 复制代码
# 错误的代码逻辑
q.append((x_start, y_start))
while q:
    x, y = q.popleft()
    maze[x][y] = 1  # 错误!在这里标记
    # ...
    # 遍历邻居,将未标记的邻居入队
    if ... and maze[next_x][next_y] != 1:
        q.append((next_x, next_y))

我是在一个节点出队时 才将它标记为已访问。这意味着,在某个节点 (x, y) 还在队列中等待处理时,如果有其他路径也通向它,它就会被重复地加入队列。这导致队列中塞满了大量重复的坐标,程序做了很多无用功,效率大大降低,最终导致了超时。

解决方法

我意识到,我必须在节点入队时就立即将其标记为已访问。这样,每个可通行的节点只会被加入队列一次,大大减少了重复计算。

我将代码做了如下修改:

python 复制代码
# 正确的代码逻辑
q.append((x_start, y_start))
maze[x_start][y_start] = 1 # 改动:起点入队时就标记

while q:
    x, y = q.popleft()
    # ...
    for candidate in wait_list:
        next_x, next_y = candidate
        if in_maze(...) and maze[next_x][next_y] != 1:
            q.append(candidate)
            maze[next_x][next_y] = 1 # 改动:入队时立即标记

这次修改后,我的代码顺利通过了所有测试点。通过这个过程,我深刻理解了 BFS 中"何时标记已访问"这个细节的重要性,它直接决定了算法的效率。

相关推荐
风中的微尘1 小时前
39.网络流入门
开发语言·网络·c++·算法
西红柿维生素2 小时前
JVM相关总结
java·jvm·算法
ChillJavaGuy4 小时前
常见限流算法详解与对比
java·算法·限流算法
sali-tec4 小时前
C# 基于halcon的视觉工作流-章34-环状测量
开发语言·图像处理·算法·计算机视觉·c#
你怎么知道我是队长5 小时前
C语言---循环结构
c语言·开发语言·算法
艾醒5 小时前
大模型面试题剖析:RAG中的文本分割策略
人工智能·算法
纪元A梦7 小时前
贪心算法应用:K-Means++初始化详解
算法·贪心算法·kmeans
_不会dp不改名_8 小时前
leetcode_21 合并两个有序链表
算法·leetcode·链表
mark-puls8 小时前
C语言打印爱心
c语言·开发语言·算法
Python技术极客8 小时前
将 Python 应用打包成 exe 软件,仅需一行代码搞定!
算法