首页 / 算法动画 / 迷宫深度优先搜索

迷宫深度优先搜索动画

网格迷宫逐格探路,死胡同标红回溯

时间复杂度 O(R·C) 空间复杂度 O(R·C) 稳定
动画加载中…

迷宫深度优先搜索(Maze DFS)

算法原理

把 DFS 放进网格迷宫:每个通路格是一个节点,相邻通路格之间有一条边——迷宫求解就成了"从起点 S 到出口 E 的图搜索"。网格 DFS 的特色是方向顺序:每走进一格,按固定次序(本动画为右 → 下 → 左 → 上)尝试四邻,第一个没去过的方向就扎进去;四个方向全撞墙或已走过,这一格就被判定为死胡同,回溯到上一格换方向。走到死胡同再退出来,正是 DFS 与"碰壁"短兵相接的样子。

本动画在 6×4 的小迷宫上演完整求解(S 左上 (0,0),E 左下 (3,0)):

S . . . . .      右上 (0,5)、右下 (3,5) 是两处死胡同,
. . # . . #      (1,3) 是死角;(3,2) 封死左下走廊——
. . # . . #      DFS 必须先进死胡同、再长链回退,
. . # . . E      最后改道左列才摸到 E。

节拍:访问拍一格(入路径),死路拍一拍(标红 + 光点折返),E 前共有 3 处主动撞壁 + 一整段右侧分支的连锁回退。全片 30 拍(2s/拍 ≈ 60s):访问 17 格、死路标注 11 拍,最终路径只剩 6 格——被标红的 11 格就是 DFS 替你排除的错误答案。

动画怎么看

  • 绿格:当前路径上的格子(相当于递归栈的内容);
  • 红格:死胡同——曾走进去、已确认四路不通而放弃的格子,终身留红;
  • 暗格:未访问 / 墙;
  • warning 光点:探查者,从格心滑到格心;死路拍它沿原路倒退回上一格;
  • 绿框格:出口 E,边框高亮;找到时整格转绿收大✓;
  • 状态行:访问 (r,c) | 入路径 / 回溯 (r,c) | 死路 / ✓ 完成 | 访问 17 格 · 路径 6——访问数含死路格,路径数只算最终从 S 到 E 的那一条。

复杂度分析

项目复杂度说明
时间O(R·C)每格至多进出一次(访问过即不再入);本动画 17 格访问、无重复
空间O(R·C)递归栈 / 路径栈最深等于最长蛇形通道;visited 标记 O(R·C)
找到的路不保证最短是"一条"通路,不一定是最短通路;最短路请用 BFS

C++ 参考代码

#include <iostream>
using namespace std;

const int R = 4, C = 6;
int maze[R][C] = {          // 0 = 通路,1 = 墙
    {0, 0, 0, 0, 0, 0},
    {0, 0, 1, 0, 0, 1},
    {0, 0, 1, 0, 0, 1},
    {0, 0, 1, 0, 0, 0},
};
bool vis[R][C];
int pathR[R * C], pathC[R * C], len = 0;   // 当前路径栈

// 右、下、左、上;找到 E 即一路返回 true(剪枝)
bool dfs(int r, int c) {
    vis[r][c] = true;
    pathR[len] = r; pathC[len] = c; len++;  // 入路径
    cout << "访问 (" << r << "," << c << ")\n";
    if (r == 3 && c == 0) return true;      // 到达 E
    int dr[] = {0, 1, 0, -1}, dc[] = {1, 0, -1, 0};
    for (int d = 0; d < 4; d++) {
        int nr = r + dr[d], nc = c + dc[d];
        if (nr < 0 || nc < 0 || nr >= R || nc >= C) continue;
        if (maze[nr][nc] == 0 && !vis[nr][nc] && dfs(nr, nc))
            return true;
    }
    len--;                                   // 回溯:出路径
    cout << "回溯 (" << r << "," << c << ") | 死路\n";
    return false;
}

int main() {
    dfs(0, 0);   // 终路径 6 格:(0,0)(0,1)(1,1)(2,1)(3,1)(3,0)
    return 0;
}

什么时候用迷宫 DFS

迷宫/网格上问"有没有路""走出所有路径""最大连通区域"时,网格 DFS 是第一反应:洪水填充(flood fill)、岛屿问题、扫雷展开,全是它的马甲。它还有一个 BFS 给不了的妙用:记录完整当前路径——路径栈里始终躺着"从 S 到这里走了哪几步",适合需要输出具体走法的场景。要最短出路时换 BFS(首次到达即最短);带权网格(进门要钥匙、格子有代价)则轮到 Dijkstra。实现上最容易错的是边界与访问标记:出界先判、进格先标,漏一步就是死循环或重复访问——本动画里每个红格都在提醒你:这一格曾经被认真走进去过。