设想你是一名山地向导,要带着登山队从山脚营地登上山顶。山路四通八达,岔路口极多,每条路的长短不一。你手里有一张手绘地图——上面标注的并不是实际距离,而是“从每个路口到山顶还剩多远”的估算值。每到一个岔路口,你都要盘算两笔账:从营地走到这里已经花了多少力气(已行路程),以及地图上还写着多少个“弯”(剩余估算)。两笔账加在一起,就是你决定往哪儿走的“总信心值”。你会优先选择总信心值最小的方向——这,就是 A* 算法最朴素的生活原型。 可如果这张地图不靠谱呢?假设地图把一条实际还剩 10 公里的路标成“只剩 2 公里”,算法就会过于乐观地冲上去;反过来,把一条近路标成“还有 20 公里”,算法又会畏首畏尾,绕远路甚至找不到山顶。前者关乎“不能夸大困难”,后者关乎“相邻路口的估算要自洽”。前者叫可采纳性(Admissible),后者叫一致性(Consistent)。本文就用向导小明登山这张地图,把这两个条件、它们的验证方法以及常用设计技巧讲透,让你既能看懂 A* 的数学公式,也能在真实工程里选对、造对启发式函数。
对 AI 从业者来说,可采纳性与一致性直接决定搜索算法能否返回最优解、以及搜索耗时是否可接受,是路径规划、游戏 AI、机器人导航等系统的性能基石。
目录
可视化演示
展示A*算法在网格地图上的启发式搜索过程:f(n)=g(n)+h(n),蓝色为已展开节点,橙色为待探索节点,绿色为最终路径。
本节配有交互动效(进入视口后自动加载,约 3KB)。
A*启发式搜索过程 起点S:搜索起始节点 已展开:closed集中的节点 待探索:open集中的节点 f(n) = g(n) + h(n) 曼哈顿距离h(n)满足可采纳性,保证A*找到最短路径。
算法基础——“总信心值”怎么算
向导小明站在山脚的营地,面前是密密麻麻的岔路。他不慌不忙,掏出两样工具:一块记步手表——从营地走到现在这个路口,走了多少步,这是精确已知的;一张手绘地图——每个路口都标注着“到山顶的估算剩余距离”。他把“已走过的步数”和“估算剩余的距离”加起来,得到的就是这个岔路口的“总信心值”。小明总选择总信心值最小的路口先探路,这就是 A* 搜索的本质动作。
在计算机里,这个“总信心值”被写成评价函数 f(n)。其中 g(n) 是从起点到节点 n 的真实代价,搜索过程中可以通过累加精确获得;h(n) 则是从 n 到目标代价的启发式估计,来自问题的领域知识。A* 维护一个按 f 值排序的开放列表(open list),每次取出 f 最小的节点扩展,直到目标节点被弹出。
你看,g 像手表那样可靠,h 则像地图那样充满“估算”的味道。A* 的全部智慧,就藏在这个 h 应该如何设计、如何约束之中。地图画得好不好,直接决定了小明能不能少走冤枉路、最终能否准时登顶。
- f(n) 总估价f 表示从起点出发、途经当前节点、最终到达目标点的全程估计代价,是 A* 决策的唯一依据。
- g(n) 已行代价g 记录起点到当前节点已经花费的实际代价,从父节点继承后再加上一步的边代价即可精确得到。
- h(n) 剩余估算h 是对当前节点到目标剩余代价的启发式预测,由领域知识构造,是整个评分中唯一“不确定”的部分。
可采纳性条件——地图不能夸大困难
假如小明手里的地图是“悲观主义者”画的:明明从这条路到山顶只剩 2 公里,地图却标注“还有 15 公里”。于是这个路口的 f 值被虚抬得很高,A* 每次优先排序时都会冷落它,转而去探索那些“看似更近”的绕远路。结果队伍辛辛苦苦绕了一大圈,才恍然发现原来那条近路才是最优的——可惜已经在错误方向上浪费了大量体力。这正是启发式函数“夸大困难”带来的恶果。
要避免这种误导,启发式函数必须满足可采纳性条件:对任意节点 n,h(n) 都不能超过从 n 到目标的真实最小代价 h*(n)。换句话说,估计只允许乐观偏低,不允许悲观偏高。只要满足这个条件,A* 在第一次从开放列表中弹出目标节点时,得到的路径一定是最优的。
所以,一张好地图的品格是“谦逊”:可以低估前方的路(多走几步冤枉路),但绝不高估困难(否则会错过最优路线)。不过请你记住,可采纳性只保证了“最终找到最优解”,它并没有承诺搜索过程一定高效——这就是我们接下来要讲一致性条件的原因。
- h*(n) 真实剩余h*(n) 表示从节点 n 到目标节点的真实最小代价,是所有可行路径代价的下确界,也是理论上不可欺骗的基准。
- h(n) 估计值启发式函数 h 输出的是对真实剩余代价的估算,它允许保守(低于真实),但不允许自大(高于真实)。
- 可采纳不等式将估计值与真实值比较,要求估计不大于真实,这就是“地图不夸大困难”的数学表达。
一致性条件——相邻路口的估算要自洽
想象小明走到一个路口,看地图说“到山顶还剩 5 公里”。他沿着山路走了 500 米,停下来再次看地图,却赫然写着“还剩 100 米”。队伍沸腾了,以为马上到顶,结果翻过垭口才发现下面是万丈悬崖,还要绕 4.5 公里。这个场景意味着什么?两个相邻路口之间的估算落差(5 公里减 100 米,约 4.9 公里)远远超过了实际走过的路程(500 米)。这种“估算突然跳水”的地图,会让 A* 算法产生一个严重后果:f 值沿路径不升反降,算法需要反复回到已探索过的节点,重新计算、重复展开,效率暴跌。
正式地,一致性条件要求对图中任意相邻节点 n 和 n',启发式函数的取值满足:h(n) 不超过“从 n 到 n' 的实际代价 c(n, n') 再加上 h(n')”。这个式子形似几何中的三角不等式,它把两个相邻节点的估计用真实边权捏合在一起,防止估算在一步之间过度跳变。
有了这把“自洽”的尺子,A* 沿任意路径推进时,f 值都只会单调不减。这就好比小明每走一段路,心中的“总信心值”只增不减,整个探索过程一路向前,不需要频繁回头。你会发现,一致性这个条件比可采纳性更“苛刻”,但正是这份苛刻,换来了搜索效率的大幅提升。
- c(n,n') 边代价c(n,n') 表示从节点 n 走到相邻节点 n' 需要付出的真实代价,在图中它是已知的边权。
- h(n') 后继估计h(n') 是到达相邻节点 n' 之后,对新位置剩余路程的启发式估算。
- 一致不等式将“当前估计”与“实际边价加后继估计”比较,防止 h 值沿边下降过快,这就是三角不等式约束。
性质关系——一致是更强的承诺
小明的队里有两位向导徒弟。徒弟甲的地图不夸大困难(可采纳),但相邻路口之间的估算经常“跳崖”(不一致);徒弟乙的地图既不大话连篇,又逐段自洽(一致)。你更愿意相信谁?显然是乙。其实从数学上看,乙的承诺确实更强:只要启发式满足一致性,并且目标节点的估计值归零,就必然同时满足可采纳性。换句话说,“一致”是“可采纳”的一个充分条件。
证明的思路非常直观:从任意节点 n 出发,沿着它到目标的最优路径 n → n₁ → n₂ → … → G 一步一步套用一致性不等式,把 h(n) 像击鼓传花一样逐级传递下去,最后一头撞上真实总代价 h*(n)。于是 h(n) 被压在了真实代价之下,可采纳性得证。反过来,“可采纳”却推不出“一致”,前者只是单点约束,后者是逐边约束。
这张“传递链”说明,一致性是比可采纳性更严格的资质认证。在实际工程中,如果你能构造出一致的启发式,就等于同时拿到了“最优性”与“不重开节点”的双重保险;而如果只能保证可采纳,则还要在搜索中处理节点重复展开的问题。
- 取最优路径设 n 到目标 G 的最优路径为 n→n₁→n₂→…→G,其真实总代价恰为 h*(n)。
- 沿路径套用一致性对路径上每条相邻边,都套用一致性不等式,得到当前估计的上界递推式。
- 逐级放大至目标把上一级的结果代入下一级,反复展开直到目标,最终整串代价相加恰好不超过真实最优代价。
验证方法——出发前逐段核对地图
小明出发前有个好习惯:把地图铺在桌上,沿着每一条山路逐段核对。他手里拿着一把直尺和一块秒表,对每一对相邻路口 n 和 n',都做一次心算:地图上 n 处的剩余路程,减去 n' 处的剩余路程,这个落差绝不允许超过两路口之间实际要走的路程。只要所有相邻对都过了关,这张地图就是一致的。
把一致性不等式移项,就能得到这个更便于工程检查的形式:h(n) - h(n') ≤ c(n, n')。于是验证流程变得非常机械:遍历图中所有有向边,逐条检查落差。除此之外还有两个边界项必须确认:第一,目标节点自身的 h 值必须为 0,否则它的估计会被“高估”;第二,若图中存在孤立节点或不可达区域,要单独核对。这两步合起来,就是完整的“一致性体检”。
这段“核对地图”的功夫,在工程上就是一行行自动化测试。造好一个启发式函数后,先用程序遍历所有相邻对,跑一遍上面的不等式,几毫秒就能判断它是否一致。这比等到搜索中途才发现反复展开节点,要划算得多。
- 移项整理将一致性不等式两边同时减去 h(n'),得到“估算落差 ≤ 实际代价”的直观形式,便于逐边验证。
- 逐边检查遍历图中每一条有向边,验证相邻节点的估算落差是否越界,这是验证算法最核心的循环。
- 终点回零目标节点到自身的真实剩余代价为 0,因此要求它的启发式估计也必须为 0,否则一致性自动失效。
常见启发式——好地图的几种款式
不同地形需要不同款式的地图。在只能横平竖直行走的城市街区里,小明用“曼哈顿距离”——就像出租车从 A 点开到 B 点,只能沿街道转向,把东西向差距和南北向差距相加。在可以翻山越岭任意直行的开阔原野上,他改用“欧氏距离”,拿尺子直接量两点间直线长度。前者是最经典的可采纳且一致启发式,在网格路径规划中几乎是无脑首选;后者在连续空间中同样满足两个条件。
还有一种更精巧的设计思路叫“松弛化”:把原问题的某些约束放宽,再用放宽后的最优解作为启发式。例如八数码游戏中,忽略“空格一次只能移动一张牌”的约束,只计算每个棋子到目标位置的曼哈顿距离之和,得到的值一定不会超过真实步数,因此天然可采纳;又因为每走一步最多让总和减少 1,它也满足一致性。
选对地图的“款式”,等于给搜索装上了涡轮增压。一张贴合问题结构、满足两种性质的地图,能让 A* 像老马识途一样直奔目标;而一张随随便便的地图,则会让算法像无头苍蝇一样到处乱撞。
- x 轴差距当前节点与目标节点在 x 方向上的坐标差,取绝对值得到横向距离。
- y 轴差距y 方向上的坐标差,同样取绝对值得到纵向距离。
- 求和得曼哈顿距离将横向与纵向相加,即四方向网格中至少需要移动的步数,是既乐观又自洽的估计。
效率影响——好地图省腿力
同样是带队登顶,徒弟乙拿着好地图,每到一个路口只需探一次就再不回头;徒弟甲的地图虽然不夸大困难,却因为相邻估算落差失控,队伍几次三番折返,同一个岔路口走了三四遍。在 A* 里,“折返”对应着节点的重复扩展:一个已经进入关闭列表(closed list)的节点,竟因为新的 g 值更优而被迫重新打开,既浪费时间又污染路径图。而一致性条件从根上杜绝了这种局面。
原因在于,一致性保证 f 值沿任意路径单调不减。当某个节点第一次被扩展时,它的 f 值不会比将来任何绕路到达它的方式更大,因此第一次到达它时的 g 值就是全局最优——关闭列表里的节点从此不再需要被唤醒。随着启发式估计越接近真实代价,扩展的节点数越少;而 h=0 的极端情况虽然也满足两个条件,却退化成盲目搜索,展开的节点数最多,好比手里没有地图、只能一寸寸摸索。
可见,一张既一致又贴合真实代价的地图,是搜索效率的双引擎。可采纳性守护最优性,一致性守护流畅性,两者齐备,A* 才能在有穷时间内给出一条漂亮的黄金路线。下山后,小明把这两条铁律刻进了登山手册的第一页,也刻进了每一位算法工程师的脑海。
- 后一节点评分扩展 n 到相邻节点 n' 后,n' 的 f 值由“起点到 n 的 g 值、n 到 n' 的边代价、n' 的估计值”三部分构成。
- 代入一致性条件由 h(n) ≤ c(n,n') + h(n') 可知,边代价与后继估计之和不小于当前节点的估计值。
- 得单调不降结论因而 f(n') 不小于 f(n),沿扩展路径 f 值只升不降,印证了“已扩展节点无需重开”。
AI 应用场景
游戏 NPC 寻路
阶段:搜索与决策
解决的问题:在庞大开放世界地图中,NPC 需要实时绕开障碍找到玩家。若启发式不一致,NPC 会在墙角反复横跳、走向抖动,玩家看到的就是“鬼畜”;若不可采纳,NPC 可能抄一条观感很差的绕路。一致且可采纳的启发式(如曼哈顿距离)让 NPC 的路径即时、平滑且最优。
具体案例:某开放世界手游中,上千个 NPC 同时寻路。采用曼哈顿距离作为启发式,提前用遍历验证一致性后,单帧寻路耗时从 8ms 降到 1.2ms,且彻底消除了“NPC 在门口反复掉头”的 bug。
仓库机器人导航
阶段:路径规划与调度
解决的问题:Kiva 式仓库里上百台机器人共享网格地面,每条任务都要在几百毫秒内算出最优路线。传统做法用 Dijkstra(等价于 h=0)虽然保证最优,但展开节点过多;采用一致性启发式后,机器人不仅走最优路径,还因为免重开机制而响应极快,能应对高频调度。
具体案例:某电商仓库中,AGV 在 300×200 的栅格地图上执行拣货任务。将曼哈顿距离与障碍物松弛化设计结合,通过一致性校验后,平均规划耗时从 45ms 降至 6ms,多机冲突率下降 70%。
拼图类 AI 解题器
阶段:状态空间搜索
解决的问题:八数码、15 数码等滑动拼图的求解器,本质是在状态图上做 A* 搜索。启发式设计的好坏直接决定“秒解”还是“穷举到死”。以曼哈顿距离之和作为启发式,配合一致性验证,求解器在保证最优解的同时,展开节点数比错误启发式少两个数量级。
具体案例:某在线 AI 课堂设计八数码求解器时,对比了三种启发式:h=0、错位棋子数、曼哈顿距离之和。一致性验证通过后,曼哈顿方案平均只展开 180 个节点,而 h=0 方案展开超过 3 万个节点。
Python 演示
import heapqimport math def verify_consistent(grid, goal, h_func): """依次检查每对相邻节点是否满足 h(n) <= c(n,n') + h(n').""" rows, cols = len(grid), len(grid[0]) h = {(r, c): h_func((r, c), goal) for r in range(rows) for c in range(cols)} for (r, c), hv in h.items(): for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)): nr, nc = r + dr, c + dc if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 0: if hv > h[(nr, nc)] + 1: return False, (r, c, nr, nc) return True, None def manhattan(node, goal): return abs(node[0] - goal[0]) + abs(node[1] - goal[1]) def euclidean(node, goal): return math.hypot(node[0] - goal[0], node[1] - goal[1]) def twice_manhattan(node, goal): return 2 * manhattan(node, goal) def astar(grid, start, goal, h_func): rows, cols = len(grid), len(grid[0]) heap = [(h_func(start, goal), 0, start)] g_best = {start: 0} parent = {} expanded = 0 while heap: f, g, node = heapq.heappop(heap) if node == goal: path = [] while node in parent: path.append(node) node = parent[node] path.append(start) return list(reversed(path)), expanded, g_best[goal] if g > g_best.get(node, float('inf')): continue expanded += 1 for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)): nr, nc = node[0] + dr, node[1] + dc if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == 0: nxt = (nr, nc) ng = g + 1 if ng < g_best.get(nxt, float('inf')): g_best[nxt] = ng parent[nxt] = node heapq.heappush(heap, (ng + h_func(nxt, goal), ng, nxt)) return None, expanded, None def main(): grid = [ [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], ] start, goal = (0, 0), (4, 4) for name, h_func in (("manhattan", manhattan), ("euclidean", euclidean), ("2x_manhattan", twice_manhattan)): ok, pos = verify_consistent(grid, goal, h_func) path, expanded, cost = astar(grid, start, goal, h_func) print(name, "consistent:", ok, "expanded:", expanded, "cost:", cost) if pos: print(" violated at", pos) if __name__ == "__main__": main()
h = {(r, c): h_func((r, c), goal) for r in range(rows) for c in range(cols)}预先为网格中每个格子算好启发式值,避免验证时重复计算。if hv > h[(nr, nc)] + 1:核心一致性检查:当前格估计值超过“相邻格估计值 + 边代价 1”即违规。heap = [(h_func(start, goal), 0, start)]初始将起点以 (f, g, 节点) 三元组压入优先队列,f 越小越先扩展。if g > g_best.get(node, float('inf')): continue若该节点已有更优路径,则跳过本次出队,等价于处理节点重开。heapq.heappush(heap, (ng + h_func(nxt, goal), ng, nxt))用新的 g 值加上启发式估计构成 f 值压堆,驱动搜索方向。
常见误区
误区我以为只要启发式函数不高估真实代价(可采纳),那就万事大吉了,搜索效率也自然最优。
正解可采纳性只保证 A* 能找到最优解,并不保证节点只被扩展一次。一个可采纳但“相邻估算落差过大”的启发式,会让 f 值沿路径下降,导致节点反复进出关闭列表,效率大幅受损。一致性是比可采纳性更强的逐边约束,两者是“及格”与“优秀”的关系。
为何常见:教科书常先证明可采纳性实现最优,读者容易误以为满足它就够了,忽视了搜索过程中的重复展开。
误区我觉得 h 值算得越“激进”、数值越大,越能体现领域知识,搜索应该越快。
正解h 值一旦超过真实代价就违反可采纳性,A* 不再保证最优;即便控制在可采纳范围内,如果它破坏了“相邻落差不超过边代价”的一致性,同样会因为节点重开而变慢。正确的策略是在可采纳且一致的前提下,尽量让 h 贴近真实代价。
为何常见:直觉上“更精确”与“数值更大”常被混为一谈,实际上精确度取决于与真实代价的贴合度,而非绝对大小。
误区h=0 肯定可采纳也一致,用它最保险,最多慢一点。
正解h=0 确实满足两个性质,但它等于放弃所有领域信息,A* 退化为 Dijkstra,节点展开数可达曼哈顿启发式的数百倍。在实时系统中,这种“保险”可能导致无法接受的延迟。一致性只是“不重复扩展”,真正决定扩展范围的是 h 与真实代价的贴近程度。
为何常见:学习者看到 h=0 满足所有数学条件,就误以为它是“零风险方案”,忽略了效率这个工程维度。
误区所有网格地图都能用曼哈顿距离当启发式,结果一定最优。
正解曼哈顿距离成立的前提是“仅允许上下左右四方向移动、且每步代价为 1”。如果地图允许对角线移动,真实最短路径可能短于曼哈顿距离,此时它反而高估真实代价,破坏可采纳性。选启发式前必须先确认移动代价模型。常用验证脚本对所有相邻节点对做一致性检查,能快速暴露这类设计失误。
为何常见:许多入门教程以四方向网格为默认场景,读者未注意假设条件,照搬到对角移动或带权图时出错。
面试题
Q1. 在 A* 的评价函数 f(n) = g(n) + h(n) 中,哪一项表示“从当前节点到目标的启发式估计”?
- A.f(n)
- B.g(n)
- C.h(n)← 正确答案
- D.c(n, n')
答案:C。g(n) 是从起点到当前节点的实际代价,h(n) 才是对剩余代价的启发式估计,两者相加得到 f(n)。c(n,n') 是相邻节点的边代价,与题意不符。可类比向导的“已走步数”与“地图剩余估算”两个角色。
Q2. 可采纳性条件的数学表述是?
- A.h(n) ≥ h*(n)
- B.h(n) ≤ h*(n)← 正确答案
- C.g(n) ≤ g*(n)
- D.f(n) ≤ f*(n)
答案:B。可采纳性要求启发式估计 h(n) 不超过真实最小代价 h*(n),即“地图不夸大困难”。若 h(n) ≥ h*(n) 表示过度悲观,A* 可能放弃最优路径。g 是已知代价,f 是综合评分,均不是约束对象。
Q3. 一致性条件的数学形式是?
- A.h(n) ≥ c(n, n') + h(n')
- B.h(n) ≤ c(n, n') + h(n')← 正确答案
- C.h(n) ≤ h(n') - c(n, n')
- D.g(n) ≤ g(n') + c(n, n')
答案:B。一致性要求当前节点估计不超过“边代价加后继节点估计”,即三角不等式。它保证相邻路口的估算不会突然跳水,从而让 f 值沿路径单调不减。B 选项正是这个关系;A 方向相反,C、D 公式不成立。
Q4. 若启发式函数满足一致性,A* 搜索可以获得哪项关键性质?
- A.已扩展节点无需重新打开← 正确答案
- B.开放列表永远为空
- C.启发式值必须为零
- D.不必维护关闭列表
答案:A。一致性保证 f 值单调不减,因此节点第一次被扩展时 g 值已是最优,关闭列表中的节点不必重开。A 正确;开放列表仍可能非空,启发式不必为零,关闭列表在一致性下仍然用于防止重复扩展,故 B、C、D 均错。
Q5. 关于 h(n)=0 的说法,正确的是?
- A.不可采纳,A* 找不到解
- B.可采纳但违反一致性
- C.可采纳且一致,但搜索效率很低← 正确答案
- D.一定会导致死循环
答案:C。h=0 时估计不高于真实代价,故可采纳;任意相邻节点间 0 ≤ c(n,n')+0 恒成立,故也一致。但它不携带任何启发信息,A* 退化为 Dijkstra,展开节点数极多,故选 C。
Q6. 若启发式满足可采纳性但不满足一致性,可能出现哪些现象?
- A.A* 必然找不到最优解
- B.某些节点可能被多次扩展← 正确答案
- C.f 值可能沿路径下降← 正确答案
- D.搜索必然提前终止
答案:BC。可采纳性保证了最优解,故 A 错;不一致意味着相邻估算落差过大,f 值可能沿某条路径下降,使已扩展节点被更优 g 值“唤醒”而重开,B、C 正确。搜索终止条件与一致性无关,D 错。可类比向导地图“相邻路口跳崖”导致队伍折返。
Q7. 在仅允许四方向移动、每步代价为 1 的网格地图上,哪些启发式函数可采纳且一致?
- A.曼哈顿距离← 正确答案
- B.欧氏距离← 正确答案
- C.两倍曼哈顿距离
- D.切比雪夫距离(max(|Δx|,|Δy|))← 正确答案
答案:ABD。真实最短路径代价恰为曼哈顿距离,A 中 h 等于下界故可采纳且一致;欧氏距离不大于曼哈顿距离且相邻变化不超过 1,故 B 正确;切比雪夫距离是曼哈顿距离的下界且每步变化不超过 1,故 D 正确;C 中两倍曼哈顿距离超过真实代价,违反可采纳性。
Q8. 在允许对角线移动且对角步代价为 1 的网格中,曼哈顿距离可能发生什么?
- A.仍然可采纳且一致
- B.高估真实代价,破坏可采纳性← 正确答案
- C.仍然一致但不可采纳
- D.退化为欧氏距离
答案:B。对角线移动使真实最短路径短于曼哈顿距离,此时曼哈顿值高于真实代价,违反可采纳性。选启发式前必须先明确移动代价模型,不能在四方向假设外盲目套用。
Q9. 工程上验证一个启发式是否一致,最直接的做法是?
- A.只检查目标节点的 h 是否为 0
- B.遍历所有相邻节点对,检查 h(n)-h(n') ≤ c(n,n'),并确认 h(goal)=0← 正确答案
- C.把启发式值取平方后再比较
- D.运行一次 A* 看路径是否平滑
答案:B。一致性是逐边约束,必须遍历所有有向边核对估算落差,同时校验目标点 h 归零,B 描述的正是标准流程。A 只是边界条件之一;C 是数值变换,无意义;D 属于事后观察,既不可靠也无法定位违规边。
Q10. 若 h₁ 与 h₂ 都满足可采纳性,那么 h(n)=max(h₁(n), h₂(n)) 一定怎样?
- A.一定可采纳且一致
- B.一定可采纳,但不一定一致← 正确答案
- C.一定一致但不可采纳
- D.一定不可采纳
答案:B。由于 h₁、h₂ 都不超过真实代价,二者取 max 仍不超过真实代价,故可采纳性保持。但取 max 可能让相邻节点的估算落差变大,破坏“落差 ≤ 边代价”的一致条件,因此不一定一致。可类比两张地图各取较保守标注,整体未必逐段自洽。