📘 教案 14:DFS / BFS 搜索进阶(与回溯的统一理解)
一、问题本质
在很多问题中,我们面对的不是数组,而是一个"状态空间"。
例如:
- 迷宫中从起点走到终点
- 在棋盘上放置棋子(如 N 皇后)
- 在字符串中逐步构造答案
- 在图中寻找路径
这些问题本质上都是:
在一个巨大的"可能性空间"中,寻找满足条件的路径或结果。
二、统一视角:搜索 = 在状态空间中移动
可以把所有问题抽象为:
- 每个"状态"是一个节点
- 每个"选择"是一条边
- 整体构成一张隐式图
因此:
所谓搜索算法,本质是在一张"隐式图"上进行遍历。
三、DFS:深度优先搜索(Depth-First Search)
1. 基本思想
从一个状态出发,沿着一条路径不断深入,直到:
- 找到解
- 或无法继续
然后回退,尝试其他路径。
2. 与回溯的关系(关键)
回溯其实就是:
带约束的 DFS
区别在于:
- DFS:只是遍历
- 回溯:在 DFS 过程中"筛选合法路径"
3. 结构模型
python
def dfs(state):
if state 满足条件:
记录结果
return
for next_state in 所有可能选择:
if 不合法:
continue
做选择
dfs(next_state)
撤销选择
4. 核心特征
- 走一条路走到底
- 使用递归(或栈)
- 适合"找所有解"或"构造解"
四、BFS:广度优先搜索(Breadth-First Search)
1. 基本思想
从起点出发,逐层扩展:
- 先访问所有"距离为1"的状态
- 再访问所有"距离为2"的状态
- 以此类推
2. 结构模型
python
from collections import deque
def bfs(start):
queue = deque([start])
visited = set([start])
while queue:
state = queue.popleft()
for next_state in 相邻状态:
if next_state 未访问:
visited.add(next_state)
queue.append(next_state)
3. 核心特征
- 一层一层扩展
- 使用队列
- 第一次到达目标即为最短路径(在无权图中)
五、DFS 与 BFS 的本质区别
| 维度 | DFS | BFS |
|---|---|---|
| 搜索方向 | 深度优先 | 层级扩展 |
| 数据结构 | 栈 / 递归 | 队列 |
| 是否最短路径 | 不保证 | 保证(无权图) |
| 适合问题 | 枚举、构造 | 最短路径 |
六、与回溯的统一理解(关键部分)
可以把三者统一为一件事:
都是在"状态空间图"中搜索
但侧重点不同:
DFS(纯搜索)
- 目标:遍历
- 不关心路径合法性
回溯(DFS + 剪枝)
- 目标:找所有合法解
- 关键:剪枝
BFS
- 目标:找最短路径
- 关键:层级扩展
七、典型问题对比
1. 迷宫路径
- 找任意路径 → DFS
- 找最短路径 → BFS
2. N 皇后
- 必须用 DFS + 回溯
3. 最短步数问题(如变换问题)
- 必须用 BFS
八、一个统一示例(帮助理解)
问题:从 0 变到 target,每次可以:
- +1
- ×2
DFS 思路
- 不断尝试路径
- 可能重复走
- 可能很慢
BFS 思路
- 层层扩展
- 第一次到 target → 最短路径
👉 这个例子非常典型:
BFS = 在"操作次数最少"的意义下找最优解
九、常见错误
- DFS 忘记"撤销状态"(导致结果错误)
- BFS 忘记 visited(导致无限循环)
- 用 DFS 求最短路径(效率极差)
- 回溯没有剪枝(变成纯暴力)
十、本质总结
搜索类算法的统一本质可以表述为:
在一个隐式定义的状态空间中,通过系统地扩展状态,找到满足条件的路径或解。
更适合教学的一句话表达
DFS 是沿路径深入的搜索方式,BFS 是按层扩展的搜索方式,而回溯是在 DFS 基础上加入约束以筛选解的一种搜索策略。