图搜索基础学习笔记

复习主线:建模 → 搜索框架 → 基础算法 → A* 与启发式 → 手推 → 工程扩展。

先掌握 BFS → UCS/Dijkstra → A*;DFS、Greedy 用于对照;再按需求学习其他最短路与机器人扩展。

内容组成: 12 章、6 幅技术插图、逐步手推表、13 张概念自测卡、4 道计算/建模练习。

阅读建议: 第一次按章节顺序阅读;复习时先看第 11 节,答不清的内容再回到对应章节。

目录

  • [1. 学习目标与知识地图](#1. 学习目标与知识地图)
  • [2. 图与状态建模](#2. 图与状态建模)
  • [3. 统一搜索框架](#3. 统一搜索框架)
  • [4. 四类基础搜索策略](#4. 四类基础搜索策略)
  • [5. A* 与启发式](#5. A* 与启发式)
  • [6. 同一张图,手推 BFS、Dijkstra 和 A*](#6. 同一张图,手推 BFS、Dijkstra 和 A*)
  • [7. 其他经典最短路:Bellman--Ford 与 Floyd--Warshall](#7. 其他经典最短路:Bellman–Ford 与 Floyd–Warshall)
  • [8. 机器人路径规划中的工程扩展](#8. 机器人路径规划中的工程扩展)
  • [9. 工程建模与实现检查](#9. 工程建模与实现检查)
  • [10. 算法对比、复杂度与选型](#10. 算法对比、复杂度与选型)
  • [11. 复习卡片、练习与学习安排](#11. 复习卡片、练习与学习安排)
  • [12. 术语索引与参考资料](#12. 术语索引与参考资料)

1. 学习目标与知识地图

1.1 先抓住一条主线

核心框架

状态描述"当前情况",边决定"允许怎么走",代价决定"什么叫好",搜索策略决定"下一步检查谁"。

图搜索通常解决两个层次的问题:

  1. 可行性: 起点到目标有没有一条合法路径?
  2. 最优性: 在合法路径中,哪条总代价最小?

"找到一条路"和"找到最好的路"是不同要求。DFS 通常只能帮助回答第一个问题;Dijkstra 和满足条件的 A* 能回答第二个问题。

本笔记默认: 图有限、环境在一次搜索期间不变、边代价非负,目标可通过明确规则判断。 涉及其他条件时另行说明。这里的"最优"首先指 所建图和所定义代价下的最优 。

1.2 算法分类:分类维度可以交叉

分类角度 典型算法 需要回答的问题
不使用剩余代价估计 BFS、DFS、UCS/Dijkstra 没有目标距离估计时,如何组织探索?
使用启发式估计 Greedy、A*、Weighted A* 怎样利用对目标的估计安排搜索顺序?
最短路径问题 Dijkstra、Bellman--Ford、Floyd--Warshall、A* 怎样求最小总代价?需要单源还是全点对结果?
机器人规划扩展 D* Lite、JPS、Theta*、CBS/ECBS 地图变化、栅格加速、任意角度、多机器人分别怎么处理?

分类不能当成互斥集合

Dijkstra 既属于无信息搜索,也用于最短路径;A* 既是启发式搜索,也是满足特定条件的最短路径算法。

1.3 学完后应能独立回答

  • 为什么节点可能需要包含朝向、速度或时间?
  • BFS 找到的"最短",具体短在哪里?
  • 为什么第一次发现一个节点,不代表找到了到它的最优路径?
  • UCS 和 Dijkstra 的共同机制是什么?
  • A* 为什么用 g+h,什么时候可以保证最优?
  • 可采纳性和一致性有什么区别?什么时候必须重开节点?
  • 四邻域、八邻域分别适合什么启发式?
  • 搜索结果最优,为什么机器人仍可能无法执行?

2. 图与状态建模

2.1 把地图转换成图

图通常记为:

\mathcal{G}=(V,E)

符号/概念 含义 路径规划例子
V 节点集合 所有合法栅格状态
E 边集合 两个状态之间可执行的运动
c(u,v) 从 u 到 v 的边代价 距离、时间、能耗
S 起点 当前机器人状态
G 目标;也可推广为目标集合 目标位置及允许的朝向范围
P 路径 从起点到目标的一串节点或动作

例:四邻域栅格。 每个可通行格子是节点;上、下、左、右相邻格子之间建立合法连接;占据格及不合法连接被剔除。图也可以用邻居生成函数隐式表示,不必预先存下所有边。参考:LaValle,离散规划

2.2 节点是"状态",不一定只是"位置"

设计状态的判断准则:

给定当前状态后,是否已经能决定后续允许的动作及其代价?如果还必须询问过去的某些信息,就可能需要把这些信息加入状态。

模型 常用状态 为什么需要这些量
简化二维点机器人 (x,y) 只关心平面位置
有朝向约束的车辆 (x,y,\theta) 车头方向影响后续可行运动
加减速受限的车辆 (x,y,\theta,v) 当前速度影响刹停距离和下一步动作
考虑时变占据的规划 (x,y,t),必要时加入其他状态量 同一位置在不同时刻可能有不同安全性

典型反例:转弯有惩罚,却只按位置去重。

两条路径到达同一格子:一条从西侧来,另一条从南侧来。即使前者当前代价更低,后者也可能因为接下来的转向更少而使总路线更便宜。如果把二者视为同一状态,便可能错误地剪掉后者。

解决方式:让状态包含足以确定转弯代价的来向或朝向,例如 (x,y,d)。同时避免加入与任务无关的量,否则状态数会迅速增长。

2.3 有向图、无向图与运动约束

  • 无向图: 若能从 u 到 v,也能反向走同一连接;两方向代价相同的情形最常见。
  • 有向图: u\to v 合法,不代表 v\to u 合法,例如单行道。
  • 边的合法性必须检查整段运动: 两个端点无碰撞,不能推出中间轨迹无碰撞。
  • 状态相同的判定必须统一: 例如朝向 0 与 2\pi 应按所用模型归一化。

建模错误,搜索无法补救

如果图允许车辆横向平移,算法可能返回一条数学上连通、车辆却无法执行的路径。搜索只会遵守已经编码到图里的约束。

2.4 路径代价:最短不一定是距离最短

对路径 P=(v_0,v_1,\ldots,v_k),常见定义为:

J(P)=\sum_{i=0}^{k-1}c(v_i,v_{i+1})

边代价 算法实际优化的目标
几何长度 总距离最短
通过该段所需时间 总通行时间最短
能耗估计 总能耗最低
距离+地形惩罚+其他可加项 指定综合代价最小

若需要混合多个指标,可定义:

c=\alpha\,c_{\text{distance}}+\beta\,c_{\text{time}}+\gamma\,c_{\text{risk}}

权重应有明确含义,并处理尺度与单位。"距离 100"和"风险 0.1"直接相加,会使结果受到数值尺度支配。风险也不一定天然可加,应先建立适合任务的代价模型。

约束与代价要区分: 禁止碰撞通常应作为可行性约束;把碰撞只设为某个有限惩罚,仍可能使算法在其他路线更贵时选择碰撞路线。


3. 统一搜索框架

3.1 搜索是在计算候选路线

搜索过程中的"沿路探索",是计算机检查状态与连接;机器人通常在规划完成后才执行路线。因此,算法扩展了很多节点,不表示机器人真实走过这些位置。

不同基础算法的主要差别可以概括为: 从候选集合里,按什么规则选出下一个节点?

3.2 六个核心记录

记录 精确定义 复习时的直观说法
OPEN 已发现、仍待处理的候选记录 下一批可以检查谁
CLOSED 已扩展状态的记录;不同实现可用其他结构代替 谁已经处理过,是否需要重开
g(n) 当前已知从 S 到 n 的最小代价 已经花了多少
h(n) 从 n 到目标的剩余代价估计 预计还要花多少
f(n) A* 中的 g(n)+h(n) 经过这里的预计总代价
parent(n) 当前最佳已知到达方式中的前驱 最后如何还原路线

初始化通常设:g(S)=0,其他节点 g=+\infty,parent(S)=\varnothing。

g 不是"天然最优"

g(n) 是当前找到的最好结果,可能被后续路线改小。只有在特定算法及条件下,节点被取出时才能证明其 g 已经最优。

3.3 区分发现、取出、扩展与关闭

动作 含义 是否说明到该点的代价最优?
发现/生成 第一次得到该状态,或生成一条到达它的候选路径 通常不能
放入 OPEN 候选记录进入队列、栈或优先队列 通常不能
取出 按算法规则选出一条候选记录 取决于算法与条件
扩展 枚举该状态的合法后继并处理连接 本身不是最优性证明
关闭 将其记录为已扩展 是否永久关闭取决于更新规则

本文采用" 有效取出目标 → 终止;其他节点 → 扩展 "的约定。因此,计数时"取出节点数"和"扩展节点数"可能相差目标节点这一次。

"有效取出"表示:记录未过时,并满足当前实现的重复处理规则。

3.4 松弛:更便宜的路线就更新

扩展 u,检查邻居 v:

g_{\text{new}}=g(u)+c(u,v)

若:

g_{\text{new}}<g(v)

则更新:

g(v)\leftarrow g_{\text{new}},\qquad parent(v)\leftarrow u

并更新其候选优先级;如果所用算法要求重开,则将已关闭的 v 重新放回 OPEN。

例: 原先到 v 的最好代价为 10,新路线经 u 到达,其中 g(u)=3、c(u,v)=2。新代价为 5,因此把 g(v) 从 10 改为 5,父节点改为 u。

松弛是一次比较与更新,不能理解为"已经走到那里,再退回来重走"。

3.5 搜索骨架与终止条件

复制代码
初始化起点记录,并放入 OPEN
while OPEN 非空:
    按当前算法的规则取出候选记录
    若记录过时,或按当前规则无需再处理:
        跳过
    若当前状态满足目标条件:
        沿 parent 恢复路径并返回
    扩展当前状态:
        生成合法后继
        按算法规则执行首次发现或代价改善处理
若 OPEN 耗尽仍未找到目标:
    返回"在当前图中不存在可达目标"

这是共同结构, 不能把 BFS 的"首次发现就固定"直接复制到带权搜索中。

算法 常用安全终止方式 补充
BFS 目标出队时 等权、正确按层搜索时,首次发现目标也可终止
DFS 发现或取出目标时 返回可行路径,通常不保证最优
Dijkstra/UCS 目标以当前有效最小 g 记录取出时 需要非负边权
标准 A* 目标以当前有效最小 f 记录取出时 还需要相应启发式与更新条件
Greedy 目标取出时 不能据此证明总代价最优

带权搜索不能"看见终点就停"

在后文例图中,经 A 发现目标的路线代价为 12;此时经 B,C,D 的代价 8 路线可能还没完成。发现目标只说明已有一条可行路线。

3.6 树搜索与图搜索:区别在重复状态处理

  • 树搜索: 把不同动作序列产生的路径分别展开;同一状态可能以多个搜索树节点反复出现。
  • 图搜索: 识别相同状态,复用记录并处理重复,避免无意义的循环探索。

这里的"树搜索"不要求原始地图是一棵树。即使原图只有一条 A\leftrightarrow B 连接,树搜索也可能不断产生 A\to B\to A\to B\cdots。

去重的依据是状态;更新的依据是代价。

  • BFS:同一状态首次入队时已经得到最少边数,通常可直接标记已发现。
  • Dijkstra/A*:见过该状态后,仍可能找到更便宜路线,需要比较 g。
  • A* 使用可采纳但不一致启发式时:更便宜路线还可能要求重开 CLOSED 节点。

3.7 优先队列中的旧记录

两种常见维护方式:

  1. 降低键值: 直接修改队列中已有记录的优先级。
  2. 重复插入: 每次改善就插入新记录,取出时跳过旧记录。

采用第二种方式,可在队列记录中保存插入时的 g_{\text{saved}}。如果取出时 g_{\text{saved}}>g(n),说明已有更便宜路线,该记录已过时。

记录比较、状态哈希、邻居生成、碰撞检查都会影响实际性能。复杂度分析通常假设这些基础操作具有规定的成本。


4. 四类基础搜索策略

4.1 BFS:广度优先搜索

4.1.1 核心规则

使用 先进先出队列 ,先发现的节点先处理。搜索按边数分层:

0\text{ 步}\rightarrow1\text{ 步}\rightarrow2\text{ 步}\rightarrow\cdots

首次发现后继时,记录父节点并入队;通常就在此时标记已发现,防止同一状态重复入队。

4.1.2 能保证什么
  • 在有限图中正确去重:存在路径时能找到,不存在时能在搜索耗尽后返回失败。
  • 保证经过的 边数最少 。
  • 当每条边代价相同且为正时,边数最少也就是总代价最小。
  • 边权不同则不保证总代价最小。

例图提示: 两边的 S\to A\to G 代价为 12,四边的 S\to B\to C\to D\to G 代价为 8。BFS 优先前者,因为它的边更少。

4.1.3 适用与代价

适合等步长、等代价栅格,或寻找最少动作数。邻接表表示、基础操作为常数时间时,遍历时间为 O(|V|+|E|),额外记录通常为 O(|V|)。宽阔搜索前沿可能消耗较多内存。

复习口令

BFS 看层数,队列先进先出;等权时才把"最少边"直接当作"最小总代价"。

4.2 DFS:深度优先搜索

4.2.1 核心规则

优先深入当前分支,走到没有未处理后继时回退。通常使用 后进先出栈 或递归。

显式栈实现中,后压入的后继先被处理。因此,若希望按照 A,B,C 的顺序深入,压栈顺序往往应反过来。

4.2.2 能保证什么
  • 有限图、正确标记重复状态:能判断可达性。
  • 通常不保证最少边数,也不保证最小总代价。
  • 无限状态空间中,即使目标可达,也可能一直沿某个无限分支深入。

它适合理解回溯、遍历、连通性及搜索结构;若要枚举多条路径,访问标记还需按具体任务设计,不能直接套用"一次访问后永久排除"。

4.2.3 不要混淆两种内存结论
  • 在有限图上保存 visited 集合,DFS 额外记录通常仍为 O(|V|)。
  • 教材中"DFS 比 BFS 省内存",往往是在比较搜索树的层宽与当前深度;递归栈也可能达到 O(|V|)。

遍历时间常写为 O(|V|+|E|)。深递归还需注意调用栈限制。

复习口令

DFS 先深入再回退,擅长探索结构;第一次找到的路径通常谈不上最优。

4.3 UCS/Dijkstra:按已付代价推进

4.3.1 二者是什么关系

UCS,即 Uniform Cost Search,常译为"一致代价搜索"。 名称不表示所有边权相同。

UCS 与 Dijkstra 的核心机制相同:

\text{每次选择 OPEN 中 }g(n)\text{ 最小的有效记录}

UCS 常从"到达一个目标"的搜索角度表述;Dijkstra 常从"一个起点到各节点最短距离"的角度表述。Dijkstra 也能在目标有效取出时提前终止。参考:MIT,Dijkstra

4.3.2 为什么非负边权很关键

设当前取出的节点为 u,它的 g 是候选中最小值。其他尚未确定的路线,若还要经过若干非负代价的边,便无法靠后续延伸把总代价降到更低。

因此可以证明: 节点第一次被有效取出时,g(u) 已是到它的最优代价。 这里强调取出,不能换成首次发现。

如果允许负边,一条当前看起来很贵的路线,后面可能因为负代价而变便宜,这个证明不再成立。

4.3.3 操作步骤
  1. 起点 g=0,放入最小优先队列。
  2. 取出最小 g 的有效节点。
  3. 若为目标,恢复路径;若求全部单源距离,则继续到候选耗尽。
  4. 对所有合法后继执行松弛。
  5. 代价改善则更新父节点与候选优先级。

它在所有候选路线间比较累计代价,不是只在当前位置挑最便宜的一条出边。

4.3.4 特性
  • 有限图、非负边权:保证最优;零代价边也可以处理。
  • 不需要启发式,对目标方向没有额外偏好,可能处理许多不相关节点。
  • 邻接表与支持降低键值的二叉堆实现,常见时间复杂度为 O((|V|+|E|)\log|V|),额外记录为 O(|V|)。重复插入版本的队列可能占用 O(|E|) 记录,复杂度应按实际实现计算。

复习口令

Dijkstra 看累计代价;非负边权下,有效取出才能确定最优。

4.4 Greedy:贪心最佳优先搜索

4.4.1 核心规则

\text{优先选择 }h(n)\text{ 最小的候选节点}

它关心"从这里看,离目标还有多远",排序时不计较已经付出的 g。

在例图里,A 和 B 的启发式都为 6;若同分时先取 A,随后发现 h(G)=0,就可能直接返回总代价 12 的路线。

4.4.2 特性与误区
  • 有时能很快找到可行路线,但没有一般性的最优保证。
  • 即使 h 可采纳,Greedy 仍不一定最优; "估计不高估"不能替代对已付代价的考虑。
  • 有限图、每个状态只扩展一次且正确去重时,最终能判断可达性;无限图不能直接套用这个结论。
  • 局部看起来靠近目标的方向,可能被障碍物阻挡,导致绕行或无效探索。

复习口令

Greedy 只看剩余估计;看起来近,不代表整条路线便宜。


5. A* 与启发式

5.1 A*:已经花费+剩余估计

\boxed{f(n)=g(n)+h(n)}

每次优先取出 f 最小的有效候选记录。

候选节点 已付代价 g 剩余估计 h f=g+h
U 3 10 13
V 6 2 8

Dijkstra 先考虑 U,因为 3<6;A* 先考虑 V,因为 8<13。Greedy 也先考虑 V,但它没有把此前已付代价纳入排序。

当 h(n)=0 时,A* 的排序就变成只看 g,退化为 UCS/Dijkstra。 若同分处理方式不同,节点顺序和最终选中的某条最优路径可能不同,但最优代价应一致。

5.2 可采纳性:不能高估最优剩余代价

记 h^*(n) 为从 n 到目标的真实最小剩余代价。本文使用常见非负约定:

0\le h(n)\le h^*(n),\qquad h(G)=0

满足该条件,称 h 可采纳 。

直观理解:启发式可以低估,但若想使用相应的最优性保证,就不能把真正便宜的方向估得过贵。

例如,真实绕墙距离为 20,忽略墙后的直线距离为 8。估计 8 虽不精确,但可以是合法下界;估计 25 则高估了。

关于 f 的精确理解

可采纳的 h 是剩余最优代价的下界,但由于当前 g(n) 可能尚未最优, 不能据此断言每个候选的 g(n)+h(n) 都是全局最优路径代价的下界 。最优性证明关注最优路径上仍被正确保留的候选节点。

5.3 一致性:沿一条边,估计下降不能过快

对每条有向边 u\to v,要求:

h(u)\le c(u,v)+h(v)

这称为 一致性 。例如边代价为 2,剩余估计不能从 10 一下掉到 3;否则 10\le2+3 不成立。

在无向图里,两个方向都应满足,即:

|h(u)-h(v)|\le c(u,v)

若 h(G)=0,沿任意到目标的路径逐边应用一致性,可推出可采纳性。因此:

\text{一致性}\Rightarrow\text{可采纳性}

反向不一定成立。参考:Berkeley,启发式与一致性

条件 约束对象 对实现的意义
可采纳 当前节点到目标的整体估计 配合正确更新、必要重开等规则,可保证最优
一致 每条边两端的估计关系 标准 A* 有效取出节点时,其 g 已最优,通常不必重开

5.4 为什么不一致启发式可能要求重开

以下是独立于后文主例图的微型反例,所有箭头为有向边:

复制代码
S ──3──> A ──2──> G
└──1──> B ──1──> A

h(S)=0,h(A)=0,h(B)=3,h(G)=0

真实剩余代价为 h^*(A)=2、h^*(B)=3,因此这里的 h 可采纳。但边 B\to A 不满足一致性:

3>1+0

搜索过程:

  1. 扩展 S 后,A 的 f=3,B 的 f=4。
  2. 先扩展 A,得到目标候选 g(G)=5,关闭 A。
  3. 扩展 B,发现到 A 的更便宜路线,g(A)=1+1=2。
  4. 如果禁止重开 A: 改善无法正确传播,可能返回代价 5。
  5. 如果重开 A: 再次处理 A,将目标代价改善为 4,得到最优路线 S\to B\to A\to G。

最优性条件要成套使用

对有限非负边权图,A* 使用可采纳启发式、允许必要重开、正确松弛与去除过时记录,并在目标有效取出时结束,可保证最优。若采用"关闭后永不重开"的标准版本,应使用一致启发式。

5.5 可重开的 A* 参考伪代码

以下采用"重复插入+跳过旧记录"。队列记录保存节点、插入时的 g 和优先级;同分时使用固定规则。

复制代码
对所有节点: g = +∞,parent = 空
g[S] = 0
CLOSED = 空集合
OPEN.push(S, g_saved=0, priority=h(S))

while OPEN 非空:
    (u, g_saved) = OPEN.pop_min()

    if g_saved > g[u]:
        continue                 # 过时记录
    if u in CLOSED:
        continue                 # 此版本中无需重复处理的记录
    if u 满足目标条件:
        return 根据 parent 恢复的路径

    CLOSED.add(u)
    for 每个合法后继 v:
        candidate = g[u] + c(u,v)
        if candidate < g[v]:
            g[v] = candidate
            parent[v] = u
            CLOSED.discard(v)     # 若已关闭,允许重开
            OPEN.push(v, g_saved=g[v], priority=g[v]+h(v))

return 无可达目标

真实实现还需处理数值精度、状态编码及碰撞检测。不能随意加入较大的比较容差后,仍声称结果严格最优。

5.6 四邻域与八邻域启发式

设栅格坐标差:

d_x=|x-x_G|,\qquad d_y=|y-y_G|

下表中的距离以"格"为坐标单位,D、D_2 则为对应移动的代价。

允许动作及代价 常用启发式 直观含义
四邻域;每个水平/竖直步代价 D h=D(d_x+d_y) 横向和纵向差分别补齐,即曼哈顿距离
八邻域;直走 D、斜走 D_2,且 D\le D_2\le2D h=D\max(d_x,d_y)+(D_2-D)\min(d_x,d_y) 尽量斜走,再补足较长方向
八邻域;直走 1、斜走 \sqrt2 h=\max(d_x,d_y)+(\sqrt2-1)\min(d_x,d_y) 上一行的常见特例,称 octile distance
八邻域;直走与斜走均为 1 h=\max(d_x,d_y) 切比雪夫距离
每条边代价至少为其几何长度 h=\sqrt{d_x^2+d_y^2},并使用匹配的空间单位 起点到目标的直线距离下界

这些栅格公式相当于在忽略障碍物的放松模型中求最短代价。障碍物只限制动作或增加绕行时,下界依旧有效;如果存在传送边、额外低价动作,原来的下界就需要重新检查。参考:Amit Patel,启发式设计

反例:八邻域却用曼哈顿距离。

从 (0,0) 到 (1,1),若斜走代价是 \sqrt2,真实最短代价为 \sqrt2,曼哈顿估计却为 2,发生高估。即使只多估了一点,也不能继续套用可采纳 A* 的严格最优保证。

5.7 启发式必须匹配单位与运动模型

5.7.1 单位匹配

g 与 h 必须具有相同代价单位。

  • 距离目标:可用米表示的直线距离下界。
  • 时间目标:若存在合法速度上界 v_{\max},可使用 h=d_{\text{straight}}/v_{\max}。
  • 含非负额外惩罚的代价:可忽略这些惩罚建立下界,但要保证基础部分的尺度正确。

"已经耗时 5 秒+剩余距离 8 米"没有一致的代价含义。

5.7.2 下界的构造方法
  1. 放松约束: 暂时忽略障碍物、转弯惩罚或部分运动限制,计算更容易的乐观问题。
  2. 使用最小单位代价: 例如所有合法直走代价至少为 D,才可用 D 缩放相应距离下界。
  3. 组合多个下界: 若 h_1,h_2 都可采纳,\max(h_1,h_2) 仍可采纳;直接相加通常不行,因为可能重复计算同一部分代价。

更精确不一定总耗时更少

更紧的合法下界通常更有助于减少无关探索,但启发式自身也有计算成本。同分规则、实现及数据结构都会影响时间,不能只看扩展节点数。

5.8 Weighted A*:放宽最优性来争取效率

f_w(n)=g(n)+w\,h(n),\qquad w\ge1

  • w=1:普通 A*。
  • w>1:增加对剩余估计的偏重,往往更急于接近目标。
  • 不再一般性保证严格最优。

一个明确的充分条件集合是: 有限图、非负边权、存在可达目标、原始 h 可采纳且目标处为 0、正确松弛并允许必要重开、以固定 w 排序,在目标有效取出时终止。 此时可得:

C_{\text{result}}\le w\,C^*

其中 C^* 是同一图、同一代价模型下的最优代价。例如 w=1.2,表示结果代价保证不超过最优值的 1.2 倍;不表示结果必定变差 20%。

这个界属于满足条件的具体算法,不能只看到代码中有 g+w h 就认定成立。增大 w 也不保证在每张地图上都更快。参考:CMU,Weighted A* 的代价界

5.9 本章速记

概念 一句话
g 当前已知的最好起点到达代价
h 剩余代价估计;要检查模型、单位和下界条件
f=g+h 普通 A* 的排序依据
可采纳 对真实最优剩余代价不高估
一致 每条边上,估计下降不超过边代价
重开 已扩展节点的 g 改善后,重新处理并传播改善
终止 满足相应条件后,有效取出目标
h=0 A* 退化为 UCS/Dijkstra
Weighted A* 用代价质量界换取潜在效率收益,必须检查界的条件

6. 同一张图,手推 BFS、Dijkstra 和 A*

6.1 例图、代价与约定

本节使用一个 人为构造的无向图 。图的排版位置不表示实际距离,真正参与运算的是边权。

边 代价 边 代价
S---A 4 A---G 8
S---B 2 B---C 2
C---D 2 D---G 2
S---X 1 X---Y 1

统一约定:

  1. 起点为 S,目标为 G;每条边可以双向通行。
  2. 邻接顺序由上面的边按 S---A、A---G、S---B、B---C、C---D、D---G、S---X、X---Y 顺序加入决定。因此扩展 S 时依次检查 A、B、X。
  3. 优先级相同时,先入队的记录先取出。
  4. 三种演示均在目标被 有效取出 时结束。
  5. BFS 在首次入队时记录父节点;Dijkstra 与 A* 在发现更小的 g 时松弛更新。
  6. "有效取出"不包含跳过的旧记录,但包含最后取出的目标;"扩展"特指生成邻居。目标取出后立即返回,因此本节扩展次数比有效取出次数少 1。

6.2 BFS:优先找边数少的路线

步骤 本次取出 处理结果 处理后的队列,左端先出
0 --- S 入队 S
1 S 依次发现 A、B、X A,B,X
2 A 发现 G,记录 parent[G]=A B,X,G
3 B 发现 C X,G,C
4 X 发现 Y G,C,Y
5 G 目标出队,返回 C,Y,搜索停止

回溯:G ← A ← S。结果为:

  • 路径:S → A → G。
  • 边数:2。
  • 路径代价:4 + 8 = 12。
  • 有效取出数:5;扩展数:4。

本例展示 BFS 的保证范围

BFS 找到了边数最少的路径,但这张图的边权不同,因此这条路径不一定总代价最小。BFS 的队列顺序不使用边权。

6.3 Dijkstra:优先处理累计代价小的候选节点

初始 g[S]=0,其他节点的 g 为无穷大。候选记录按 g 排序;相同 g 按入队先后排序。

步骤 有效取出 g 值 发生的关键更新
1 S 0 A=4,B=2,X=1
2 X 1 Y=2
3 B 2 C=4
4 Y 2 没有更便宜的到达方式
5 A 4 首次发现 G,暂记 G=12、父节点为 A
6 C 4 D=6
7 D 6 经 D 到 G 只需 8,更新 G=8、父节点为 D
8 G 8 目标有效出队,返回

回溯:G ← D ← C ← B ← S。结果为:

  • 路径:S → B → C → D → G。
  • 边数:4。
  • 路径代价:2 + 2 + 2 + 2 = 8。
  • 有效取出数:8;扩展数:7。

为什么不能"第一次发现目标就返回"?

第 5 步发现 G 时,已知代价为 12;第 7 步才将其改善到 8。若在第 5 步直接结束,就会返回次优结果。

如果优先队列通过"重复插入"实现更新,第 7 步会新增一条 G=8 的记录,旧的 G=12 记录可能仍在堆中。本例在取出 G=8 后已经结束;如果继续处理堆,G=12 应被识别为过时记录并跳过。

6.4 A*:使用剩余代价下界引导搜索

采用以下启发式:

节点 S A B C D G X Y
h 8 6 6 4 2 0 9 10

这些 h 值均不超过真实最小剩余代价,且对每条双向连接满足一致性。它们是为演示构造的数值,并非由图中排版距离计算。

步骤 有效取出 g h f=g+h 关键结果
1 S 0 8 8 生成 A:f=10;B:f=8;X:f=10
2 B 2 6 8 生成 C:g=4,f=8
3 C 4 4 8 生成 D:g=6,f=8
4 D 6 2 8 生成 G:g=8,f=8
5 G 8 0 8 返回最优路径

A 与 X 的 f 都是 10。在目标以 f=8 出队之前,没有必要扩展它们。

  • 路径:S → B → C → D → G。
  • 路径代价:8,与 Dijkstra 相同。
  • 有效取出数:5;扩展数:4。

6.5 三种算法的直接对照

算法 排序依据 返回代价 边数 有效取出数,含目标 邻居扩展次数
BFS 入队顺序/搜索层数 12 2 5 4
Dijkstra g 8 4 8 7
A* g+h 8 4 5 4

本例需要记住的结论:

  1. 边数少与总代价小是两个目标。
  2. 发现一个节点,不代表到达它的最佳代价已经确定。
  3. A* 可以通过有用的下界减少实际搜索,但本例的提速比例不是通用保证。
  4. 优先级相同的处理规则会改变取出顺序,也可能改变返回哪条等价最优路径;最优总代价的保证不因此改变。

6.6 两个自检实验

实验 A:将所有边权改成 1。 此时边数最少等价于总代价最小,BFS 与 Dijkstra 返回的最优代价应一致。重新构造 h,或直接令 h=0;不能直接沿用本例原有 h 值,因为代价变小可能让旧 h 高估。

实验 B:保持原边权,把所有 h 改成 0。 A* 的排序依据变成 g。若邻接顺序、入队顺序与去重规则都一致,它应表现为 Dijkstra;至少最优代价必须一致。


7. 其他经典最短路:Bellman--Ford 与 Floyd--Warshall

本章抓住两个区别

单源 / 全点对 :从一个起点出发,还是查询任意两点?

负边 / 负环 :允许负边不等于存在有限的最短代价。

7.1 Bellman--Ford:允许负边的单源最短路

问题 :从起点 s 出发,求到各节点的最短代价;边权可以为负。

直觉 :Dijkstra 每次优先处理最便宜的候选节点;Bellman--Ford 则多轮检查所有边,让更便宜的路线不断向外传播。

定义 d_k(v) 为从 s 到 v、 最多经过 k 条边 的最小代价:

d_0(s)=0,\qquad d_0(v)=+\infty\;(v\ne s)

d_k(v)=\min\leftd_{k-1}(v),\\ \\min_{(u,v)\\in E}\\{d_{k-1}(u)+c(u,v)\\}\\right

步骤 操作 为什么这样做
1 起点距离设为 0,其余设为无穷大 尚不知道任何到达其他节点的路线
2 最多进行 \lvert V\rvert-1 轮全边松弛 不受负环影响的最短路可取为简单路径,最多含 \lvert V\rvert-1 条边
3 某轮完全没有更新时可提前停止 所有边已满足当前最短路条件
4 再检查一轮是否仍有可达边能够松弛 若有,说明存在从起点可达的负环
  • 时间复杂度:O(|V||E|)。
  • 额外空间:常见实现为 O(|V|),另加图本身的存储。
  • 公式按"上一轮快照"定义;实现也常采用原地松弛,一轮可能传播多条边, 不要再把该轮结果严格解释为最多 k 条边的结果 。

负边示例 :S\to A 代价 4,S\to B 代价 5,B\to A 代价 -3。到 A 的最优代价为 5-3=2。标准 Dijkstra 可能过早确定 A 的代价为 4;Bellman--Ford 可以继续改进。

参考:MIT:Bellman--Ford。

7.2 负环影响的准确条件

负环是 总边权小于 0 的环 。绕环次数越多,总代价越低。

对于起点 s、目标 t 对 s\to t 最短路的影响
负环不能从 s 到达 不影响这次单源搜索
s 能到负环,但负环不能到 t 不因此破坏到 t 的有限最短代价
s 能到负环,负环还能到 t 可重复绕环后前往 t,代价无下界,记为 -\infty
t 本身不可达 距离为 +\infty

不要记成"图中有负环,所有最短路都不存在"

负环只影响能够经过该环到达的相应起终点对。普通 Bellman--Ford 的额外一轮可检测 起点可达 的负环;若要检测图中任意负环,可添加连接所有节点、边权为 0 的超级源点。

这里讨论的是标准最短路模型,允许路线重复经过节点。如果强行禁止重复节点,问题的定义与求解方法会发生变化。参考:Stanford:Bellman--Ford 与 Floyd--Warshall 讲义。

7.3 Floyd--Warshall:一次计算任意两点的最短路

适用问题 :仓库只有几十个重要站点,需要反复查询任意两个站点之间的距离,而不是只规划某一对起终点。

直觉 :逐个允许新的"中转站"。每增加中转站 k,检查 i\to k\to j 是否比目前的 i\to j 更便宜。

令 D^{(k)}_{ij} 表示只允许编号 1,\ldots,k 的节点作为中间节点时,i 到 j 的最小代价:

D^{(k)}{ij}=\min\left(D^{(k-1)}{ij},\ D^{(k-1)}{ik}+D^{(k-1)}{kj}\right)

  • 初始化:对角线为 0,有边取边权,无边为 +\infty;重边取最小值,负自环应保留以便检测。
  • 标准三重循环顺序: k 在最外层 ,内部遍历 i,j。
  • 时间复杂度:O(|V|^3);使用距离矩阵的空间复杂度:O(|V|^2)。
  • 允许负边。没有负环时,得到有限距离或不可达结果。
  • 计算后若存在 D_{kk}<0,说明有负环;满足 i\leadsto k\leadsto j 的点对受到该负环影响,不应把其矩阵数值当作有限最短代价。

边界意识 :大型栅格往往有成千上万个节点,计算全部点对通常很昂贵;少量站点组成的拓扑图更适合考虑此方法。参考:MIT:全点对最短路与 Floyd--Warshall。

8. 机器人路径规划中的工程扩展

先记问题,再记算法名

变化后重规划 → D* Lite;规则栅格加速 → JPS;任意角度 → Theta*;多机器人消解冲突 → CBS / ECBS。

8.1 D* 与 D* Lite:复用已有结果进行重规划

仓库例子 :机器人沿原路径行驶,传感器发现前方临时堆放了货物。地图中的部分边变为不可通行,或代价升高。

直观过程 :

  1. 根据当前已知地图计算路径。
  2. 移动并接收新的环境信息。
  3. 更新发生变化的边代价。
  4. 复用原有搜索记录,修复受影响的部分,再继续前进。
要点 复习结论
D* Dynamic A*,通过增量修复处理行驶过程中获得的新地图信息
D* Lite 基于 LPA* 的增量启发式方法;与 Focussed D* 的导航行为相近,算法机制不同
相比重复运行 A* 有机会减少对未受影响部分的重复计算,收益取决于变化位置、规模和地图结构
最优性的范围 在算法假设与正确更新条件下,针对 当前已知图 求最短路径
不自动保证的事情 在未知真实环境中最终实际走过的总路线全局最优;预测行人未来轨迹;车辆动力学可执行性

"环境动态变化"要分清含义

地图边代价发生变化后的快速修复,与预测"行人在两秒后占据哪里"是不同问题。后一种需求还要引入时间、运动预测、时空约束或局部避障机制。

参考:Koenig 与 Likhachev:D* Lite 原始论文及摘要。

8.2 JPS:利用栅格中的对称性减少扩展

仓库例子 :大面积空旷仓储区中,从左下到右上有许多等价的最短逐格走法。逐个扩展这些中间格子会产生重复工作。

核心机制 :沿某个方向扫描,把不必要的中间扩展跳过;遇到目标、需要改变搜索结构的"跳点"等位置,再进行搜索决策。

  • 跳过的是搜索中的中间节点扩展 ,机器人仍要通过这些位置,整段连接必须无碰撞。
  • 原始 JPS 针对 均匀地形代价、规定邻接与运动规则的栅格 ;典型八邻域中,直走与斜走采用固定对应代价。
  • 在原算法假设下保留该栅格图上的最优解;障碍物形状、强制邻居等决定哪些点必须保留。
  • 随意增加地形权重、转向代价、历史相关惩罚,会破坏对称性依据,不能直接沿用原剪枝规则。
  • 搜索扩展变少不等于所有开销都消失,扫描本身仍要耗时。

参考:Harabor 与 Grastien:JPS 原始论文。

8.3 Theta*:在栅格上生成任意角度路径

仓库例子 :普通八邻域 A* 的路径呈水平、竖直和对角折线;空旷区域实际上可以沿一个其他角度直达。

核心机制 :扩展节点时,不只检查"当前节点 → 相邻节点",还尝试"当前节点的父节点 → 相邻节点"。若存在无碰撞视线,且代价更小,就更新父节点连接。

记忆要点 :

  • 搜索仍利用栅格组织信息,输出路径不必沿栅格边行走。
  • 视线检查必须验证 整条线段 ,不能只检查两端是否空闲。
  • Basic Theta* 可以找到较短的任意角度路径,但 不保证连续空间中的真正最短路径 。
  • 任意角度折线仍可能有急转弯; 不自动保证曲率、转弯半径与速度约束 。
  • 应将"路径更短、更自然"和"轨迹可执行"分开验证。

参考:Daniel 等:Theta* 论文。

8.4 CBS:多机器人的冲突分解搜索

仓库例子 :两台机器人分别从窄走廊两端出发,各自最短路径都经过走廊。单独无碰撞,不代表同时执行时没有冲突。

典型离散 MAPF 模型使用时间步,并允许"移动"与"等待"。常检查:

冲突 例子
顶点冲突 两台机器人在同一时间占据同一个节点
交换冲突 同一时间步,一台从 u\to v,另一台从 v\to u

CBS 使用两层结构:

  1. 底层 :分别为机器人寻找满足已有约束的最优路径,常用带时间状态的单机器人搜索。
  2. 上层 :检查联合方案中的冲突,建立约束树。
  3. 若 A、B 在时刻 t 冲突于位置 v,产生两个分支:一个禁止 A 在该时刻占据该位置,另一个禁止 B。
  4. 在各分支内重新规划受约束机器人,继续选择和处理冲突,直至得到无冲突方案。

最优性必须配合目标来理解 :常见 CBS 优化的是所有机器人路径代价之和(sum of costs);最大完成时间(makespan)是另一种目标,需匹配相应的排序、下界和算法设置。

局限 :机器人多、瓶颈密集、冲突反复时,约束树可能很大。实际机器人还要把车身尺寸、运动持续时间、跟踪误差等纳入碰撞模型;只有节点层面的无冲突还不够。

参考:Sharon 等:CBS 原始研究。

8.5 ECBS:用有界次优换取求解效率

ECBS 是 CBS 的有界次优扩展,利用 focal search(焦点搜索) 在允许的代价范围内,优先考虑更有希望较快消除冲突的候选节点。

  • 设容许因子为 w\ge1;满足算法的下界维护和上下层搜索条件时:

C_{\text{返回}}\le w\,C^*_{\text{MAPF}}

  • 这里的代价是所选目标下的 联合方案代价 ,不等于每台机器人的独立最短路都能同时实现。
  • w=1.1 表示最多容许相对最优联合方案高 10%;并不表示结果一定高 10%。
  • ECBS 的保证来自上下层搜索与下界之间的配合, 不能简单理解为"把底层 A* 改成 Weighted A* 就完成了 ECBS" 。
  • 更快是设计目标和常见实验表现;具体实例的运行时间仍需测量。

参考:Barer 等:CBS 的次优扩展论文;Li 等:对 CBS、ECBS 与有界次优性质的说明。

9. 工程建模与实现检查

9.1 状态是否包含决定未来所需的信息?

实际约束或目标 状态建模提示
仅位置决定后续动作与代价 可采用 (x,y)
车辆朝向影响后续可达动作 加入 \theta,如 (x,y,\theta)
转向惩罚依赖进入节点的方向 加入朝向或上一运动方向,避免错误合并
障碍物占用位置随时间变化 可能需要 (x,y,t) 或其他时空表示
加速度、制动距离取决于速度 可能需要速度等动态状态

状态合并条件

两条路线到达同一位置,只有在它们的后续可行动作和代价规律等价时,才能仅按位置比较 g 并合并。否则,"当前更便宜"不代表"后续一定更好"。

状态越完整,规模可能越大 ;应保留必要信息,再考虑离散精度与搜索加速。

9.2 几何与运动:节点安全不等于连接安全

  • 机器人尺寸 :点机器人能通过的窄缝,真实车身可能通不过。圆形机器人可按半径及必要余量膨胀障碍;复杂形状需结合姿态进行配置空间或足迹碰撞检查。
  • 角落穿越 :八邻域斜走应明确角落规则;在采用保守的禁止切角模型时,两侧直邻格都必须可通行。无论规则如何,都应与真实几何碰撞检查一致。
  • 整段连接 :边的两个端点可行,不代表中间线段或运动原语可行。
  • 运动学约束 :车辆的最小转弯半径、是否能倒车、是否能原地转向,必须体现在边或运动原语中。
  • 网格分辨率 :二维地图边长分辨率减半,单元数约增至 4 倍;狭窄通道表示更精细,但计算和存储开销增大。
  • 平滑后重验 :重新检查碰撞、净空、曲率及速度 / 加速度约束;原折线路径安全不代表平滑曲线安全。

这些检查源于配置空间建模:把机器人形状与姿态纳入可行状态和运动的定义。参考:LaValle:配置空间与障碍物。

9.3 代价与环境:先确认优化目标

检查项 正确做法
距离、时间、能耗混合 明确各项单位、尺度与权重,不能不加处理地把米与秒相加
避障风险惩罚 使用与目标一致的代价;安全禁区仍需硬约束,不能只寄希望于较大惩罚
负代价奖励 检查是否产生循环获利;常见 Dijkstra / A* 的非负代价保证可能不再适用
启发式匹配 优化时间就使用时间下界;改变运动规则、代价后重新验证 h
地图更新 使旧路径失效或触发修复,避免继续使用已被阻挡的边
动态障碍物 明确预测时域、感知延迟及等待动作;区分全局重规划与局部避障职责

风险代价的解释

c=\alpha\,\text{距离}+\beta\,\text{时间}+\gamma\,\text{风险分数} 可表达偏好;系数承担单位换算和相对重要性。只有在具体概率模型成立时,风险分数才能按相应方式解释为碰撞概率。

9.4 搜索实现:优先检查的细节

常见错误 修正原则
第一次发现节点就永久锁定 BFS 等权模型可在入队时去重;带权搜索要允许更小的 g 更新
Dijkstra / A* 一看到目标邻居就结束 在满足各自条件时,目标作为有效的最优先候选被取出才结束
A* 使用不一致启发式,却永不重开 CLOSED 更小 g 到来时应按算法要求重开并传播改进
堆中旧记录再次被当成当前最优记录处理 每条记录保存插入时的 g 或版本号,取出时对照最新记录并跳过过时条目
只更新 g,未更新父节点 同步更新父节点,保证路径回溯与最终代价一致
无路径时仍然继续回溯 OPEN 耗尽应返回"不可达",不能生成伪路径
没有固定同优先级处理规则 为复现实验设定 tie-break;它可影响路线形状和扩展数量

补充:使用浮点数比较时,应制定统一的数值策略;容差会影响严格最优性的解释。若采用惰性插入,堆可能同时含一个节点的多条记录,其内存不能再简单按"每节点一项"估算。

10. 算法对比、复杂度与选型

10.1 比较前先统一假设

下表采用: 有限显式图、正确去重、邻接表存储、边与启发式计算为常数时间 。记节点数为 N=|V|、边数为 M=|E|。"完备"表示有可行路径时能找到;本表中的有限图实现也能在搜索结束后报告不可达。

算法 完备性与最优性 典型最坏时间 额外空间,不含输入图
DFS 有限图且正确去重时完备;通常不保证最短 O(N+M) O(N)
BFS 完备;最少边数,等正边权时也是最小总代价 O(N+M) O(N)
UCS / Dijkstra 非负边权下完备且最优 支持 decrease-key 的二叉堆:O((N+M)\log N) O(N)
Greedy 有限图、正确去重并最终处理所有候选时完备;通常不最优 每节点最多扩展一次、可更新二叉堆:O((N+M)\log N) 此实现为 O(N)
A* 非负边权、可采纳 h、正确更新及必要重开时完备且最优 一致 h、无需重开、可更新二叉堆:O((N+M)\log N);一般不一致 h 可能反复扩展 单记录可更新队列实现为 O(N);惰性插入需另计旧条目
Weighted A* 上述有限图条件与正确维护下可求解;最优性通常放宽为有条件的 w 倍界 与启发式、重开和实现有关,不套用"每节点只扩展一次"结论 同样需考虑队列实现与旧条目
Bellman--Ford 允许负边;可计算不受可达负环影响的距离,并检测起点可达负环 O(NM) O(N)
Floyd--Warshall 无负环时求全部点对最短距离;可检测负环 O(N^3) O(N^2)

堆实现区别 :表中的 Dijkstra 界针对每个节点保留可更新堆项。惰性插入的常见表述为 O((N+M)\log(N+M)) 时间、O(N+M) 额外空间;简单图中常将其简化到与 \log N 同阶,但仍需交代实现。

10.2 为什么又会看到"搜索复杂度是指数级"?

这与上表不矛盾:

  • 显式图角度 :复杂度按已经给出的节点数 N、边数 M 计。
  • 隐式搜索角度 :节点按需生成。若平均分支数为 b、解深度为 d,搜索树规模可能随 b^d 增长;深度为 d 的末层可能就有 b^d 个节点。
  • 状态建模角度 :位置再乘以朝向、速度、时间、多机器人组合,N 本身就可能很大。

因此,A* 在某张图上比 Dijkstra 少扩展很多节点,并不改变困难问题可能仍然很大的事实。DFS 在树搜索中可只保存当前分支与待处理分支;本笔记的 O(N) 空间则包括图搜索去重表,不能混为一个口径。

10.3 按需求选择学习与实现起点

当前问题 可优先研究 首先验证
只想判断是否可达、练习回溯 DFS / BFS 图是否正确、是否去重
每步等价,要求步数最少 BFS 所有动作是否确实等价
非负边权,需要可靠最短路基线 Dijkstra 松弛、终止与路径回溯
单起点到目标,有有效距离下界 A* 启发式是否可采纳 / 一致
接受可控代价偏差,希望较快求解 Weighted A* w 倍保证所需实现条件、实际速度收益
有负边 Bellman--Ford 是否存在相关负环,奖励模型是否合理
小规模图,任意点对查询频繁 Floyd--Warshall N^2 内存与 N^3 时间预算
地图边代价反复更新 D* Lite 变化范围、复用收益、当前地图有效性
标准均匀地形栅格,需要搜索加速 JPS 运动与角落规则是否符合剪枝证明
希望摆脱栅格边方向限制 Theta* 视线碰撞检查与后续曲率约束
多机器人需要时空无冲突方案 CBS / ECBS 冲突定义、联合优化目标与执行误差

这是一条工程入门路线,不表示任何算法在所有地图上都最快。选型应由地图、状态、目标、时限和实验数据共同决定。

10.4 最小实验清单:用数据巩固理解

在相同地图、运动规则、代价函数与运行环境下记录:

指标 回答的问题
是否成功、路径是否有效 找到的结果能否到达并满足约束?
总代价 优化目标完成得怎样?
扩展节点数、生成节点数 搜索工作量有多大?统计口径须固定
耗时与内存峰值 能否满足系统预算?
重规划耗时 地图变化后多久能恢复可用方案?
  • 等权地图:BFS 与 Dijkstra 的最优代价一致。
  • 非负带权图:A* 取 h=0 时,最优代价与 Dijkstra 一致;有多条最优路时,具体路线可以不同。
  • 有路、无路、起点等于终点均能正确处理。
  • 加入斜走后,重新检查启发式与角落规则。
  • 地图变化、平滑处理后,重新验证路径可行性。
  • 算法比较采用固定 tie-break 和相同统计口径。

11. 复习卡片、练习与学习安排

11.1 一页速记

想解决的问题 先回想什么
地图怎样进入算法? 状态是节点,合法动作是边,动作代价是边权
怎样定义"最好"? 路径总代价,且目标、单位与权重必须明确
BFS 和 Dijkstra 有何区别? 按边数分层 vs 按累计代价 g 排序
UCS 和 Dijkstra 有何联系? 核心排序与松弛机制一致,常见任务表述不同
A* 为什么有方向感? f=g+h,用剩余代价估计引导候选顺序
A* 为什么可能不最优? h 高估、拒绝必要重开、错误去重或过早终止等
最优路径为什么可能不能执行? 图没有表达完整尺寸、姿态、运动或时间约束
图变化后如何利用旧结果? 增量搜索与 D* Lite
多个机器人怎样协调? 时空状态、等待动作、冲突约束与 CBS/ECBS

11.2 概念自测与折叠答案

Q1:BFS 一定能找到"最短路径"吗?

它保证边数最少。所有边代价相同且非负时,边数最少对应最小总代价;边权不同时,通常不保证总代价最小。还需要正确去重,并满足前文讨论的有限图等条件。

Q2:UCS 的"一致代价"是否表示每条边权相同?

否。UCS 按路径累计代价 g 从小到大选择候选,可以处理不同的非负边权。不要把它与"等权图"混为一谈。

Q3:g(n) 是否一直等于起点到 n 的真实最短代价?

否。它是当前已知的最佳到达代价。Dijkstra 有效取出某节点时,该值才在非负边权假设下确定为最优;一致启发式下标准 A* 也具有相应性质。

Q4:为什么 Dijkstra/A* 不能第一次发现目标就结束?

发现目标只得到一条候选路线;仍可能有更便宜的前缀等待扩展。本笔记例图中,Dijkstra 先发现总代价 12,后来改善为 8。标准最优搜索应在目标有效出队时按相应条件结束。

Q5:h=0 的 A* 是什么?

Dijkstra/UCS 的排序机制。若实现细节与平局规则一致,搜索过程也可一致;多个最优路径存在时,不应仅以路径节点序列是否相同判断正确性。

Q6:可采纳启发式与一致启发式是什么关系?

可采纳性限制到目标的估计不高估;一致性限制每条边上的估计变化。配合目标处 h=0,一致性蕴含可采纳性;反过来不一定成立。启发式可采纳但不一致时,图搜索需要允许 g 改善后的必要重开。

Q7:八邻域、直走 1、斜走 √2 时,曼哈顿距离可以直接保证 A* 最优吗?

通常不可以。例如从 (0,0) 到 (1,1),曼哈顿估计为 2,但斜走只需 √2,已经高估。应采用合适的八方向距离,或其他经证明合法的下界。

Q8:为了省开平方,直接把欧氏距离换成它的平方,可以吗?

不能随意替换。平方距离与距离单位不同,而且可能超过真实剩余长度,破坏可采纳性。应使用与代价模型匹配、经过验证的启发式。

Q9:Weighted A* 的 w=1.2,是否表示每次结果都比最优差 20%?

否。在满足相应理论条件和正确实现时,它给出的是不超过最优代价 1.2 倍的上界;实际结果可能就是最优解。速度也不保证随 w 单调改善。

Q10:D* Lite 是否自动解决了行人的预测避障?

否。它主要复用旧搜索信息,处理地图或边代价改变后的重规划。移动障碍物的未来轨迹、时间碰撞约束与局部避障还需另外建模或处理。

Q11:JPS 是否适合任意带权地图?

原始标准 JPS 的剪枝依赖规定的均匀代价栅格与运动规则。任意地形权重、转弯代价或不同运动约束可能破坏这些条件,不能直接照搬其最优性保证。

Q12:两台机器人的几何路径相交,一定碰撞吗?

不一定,还要看到达时间;同一位置在不同时间经过可以不冲突。但还应检查机器人尺寸,以及模型中的同一时刻占据和迎面换位等冲突。

Q13:图搜索报告"无路",是否证明真实环境绝对无路?

只能说明在当前图、动作集合和约束下未找到可达路径。过粗离散、过大的障碍膨胀或过强动作限制,都可能使真实可行路径没有被图表示出来。

11.3 计算练习

11.3.1 练习 A:检查松弛

已知 g[V]=10,g[U]=3,c(U,V)=2。是否更新 V?更新哪些记录?

参考答案

tentative=3+2=5<10,所以更新 g[V]=5 与 parent[V]=U,并更新其候选优先级。若采用重复入堆方式,插入带新 g 快照的记录,之后跳过旧记录。

11.3.2 练习 B:比较三种启发式

起点为 (0,0),目标为 (4,3),格子边长为 1。分别计算四邻域最少步数、八邻域最短长度(直走 1、斜走 √2)和直线距离。忽略障碍。

参考答案

四邻域:4+3=7。八邻域:3√2+1≈5.243。直线距离:√(4²+3²)=5。三者对应的动作模型不同;不能把 7 直接当作允许斜走问题的可采纳启发式。

11.3.3 练习 C:可采纳但不一致的反例

沿用第 5.4 节的有向反例:S→A=3、S→B=1、B→A=1、A→G=2。取 h(S)=0、h(A)=0、h(B)=3、h(G)=0。

问题:为什么这些 h 可采纳却不一致?如果 A 第一次扩展后永久禁止改善,会发生什么?

参考答案

从 B 到 G 的真实最小代价为 1+2=3,因此 h(B) 没有高估;其他节点也没有高估。但边 B→A 上,3≤1+0 不成立,所以不一致。A 首次以 g=3 出队,生成 G=5;随后 B 能将 A 改善为 g=2。若永久拒绝这个改善,会返回代价 5;允许重开 A 后,G 会被改善为 4,对应 S→B→A→G。

11.3.4 练习 D:状态是否完整

某机器人规划加入"每次转弯额外付出 3"的代价,但节点仍只有 (x,y)。这样是否总能正确使用最短路算法?

参考答案

不一定。后续转弯代价依赖到达该位置时的朝向,把不同来向合并为同一节点可能丢弃更优方案。应把相关方向信息纳入状态,例如 (x,y,heading),使后续动作和代价可由当前状态确定。

11.4 动手实现与验证顺序

阶段 任务 核心验收标准
A 有障碍的四邻域地图上实现 BFS 能恢复路径、正确报告不可达、避免环路
B 将道路代价改为非负且不相同,实现 Dijkstra 正确松弛,目标有效出队后返回,结果与小图手算一致
C 在 Dijkstra 框架上加入合法 h,形成 A* 与 Dijkstra 最优代价一致;h=0 时退化正确
D 加入反例与边界情况 覆盖起点即目标、不可达、等价最优路、零代价边、过时堆条目、必要重开
E 加入机器人约束 路径与边均经过碰撞和运动可行性检查

对每个算法统一记录: 返回代价、有效取出数、邻居扩展次数、运行时间、候选队列峰值 。计数口径应固定,不能混用"发现数""取出数"和"扩展数"。

11.5 间隔复习建议

复习轮次 建议动作 目标
学完当天 不看答案,重画算法关系图;手推第 6 节 建立结构与操作直觉
约 1 天后 回答 11.2 的问题,标记答不清的条目 检查概念是否真正掌握
约 3 天后 从空白写出 Dijkstra/A* 核心流程 掌握松弛、优先队列与终止条件
约 7 天后 做 11.3 的反例题,并解释错误实现为何失败 掌握算法保证的前提
约 14 天后 将代价改为时间或加入转弯,重新设计状态与 h 把概念迁移到工程问题

掌握度检查:

  • 能解释图、状态、边、代价函数之间的关系。
  • 能手推 BFS、Dijkstra、A*,区分发现、有效取出和扩展。
  • 能说明 UCS 与 Dijkstra 的共同机制。
  • 能写出松弛条件,并正确更新父节点。
  • 能区分可采纳性与一致性,解释重开的作用。
  • 能根据四/八邻域及代价单位选择 h。
  • 能说明 D* Lite、JPS、Theta*、CBS/ECBS 分别解决什么问题。
  • 能解释"图上最优"与"机器人可执行"之间的差别。

12. 术语索引与参考资料

12.1 中英文术语速查

中文 英文/缩写 复习定位
图、节点、边 Graph、Vertex/Node、Edge 第 2 节
状态、动作 State、Action 第 2 节
搜索前沿、候选集合 Frontier/OPEN 第 3 节
松弛 Relaxation 第 3、6 节
父节点 Parent/Predecessor 第 3 节
广度/深度优先搜索 BFS/DFS 第 4 节
一致代价搜索 Uniform Cost Search,UCS 第 4 节
贪心最佳优先搜索 Greedy Best-First Search 第 4 节
启发式 Heuristic 第 5 节
可采纳性 Admissibility 第 5 节
一致性 Consistency 第 5 节
节点重开 Reopening 第 5、11 节
完备性、最优性 Completeness、Optimality 第 10 节
有界次优 Bounded Suboptimality 第 5、8 节
增量搜索、重规划 Incremental Search、Replanning 第 8 节
跳点搜索 Jump Point Search,JPS 第 8 节
任意角度规划 Any-Angle Path Planning 第 8 节
多智能体路径规划 Multi-Agent Path Finding,MAPF 第 8 节
冲突搜索 Conflict-Based Search,CBS 第 8 节
相关推荐
淡海水1 小时前
05-02-源码-Boehm GC标记阶段
算法·unity·c#·游戏引擎·gc
Code_Solitude2 小时前
传智杯备赛代码整理(前4题)
数据结构·算法
Jasmine_llq2 小时前
《P8816 [CSP-J 2022] 上升点列》
数据结构·算法·贪心·排序·二维动态规划 dp·类背包状态转移
hetao17338372 小时前
2026-10-19 hetao1733837 的刷题记录
c++·算法
辛苦才能3 小时前
C++ 哈希表深度解析:删除为什么必须打标记,负载因子为什么卡 0.7
开发语言·数据结构·c++·算法
m0_639906943 小时前
HashMap:哈希扰动、扩容源码、红黑树转换、并发问题
java·算法·哈希算法
开开心心就好4 小时前
白天晚上自动调蓝光,护眼工具亮度可调
服务器·开发语言·算法·pdf·ocr·intellij-idea·idea
Jsundoku5 小时前
第六章 机器学习 -- 支持向量机
算法·机器学习·支持向量机