惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
阮一峰的网络日志
阮一峰的网络日志
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
量子位
Jina AI
Jina AI
Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页
L
LangChain Blog
A
About on SuperTechFans
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
美团技术团队
博客园 - 三生石上(FineUI控件)
N
Netflix TechBlog - Medium
D
DataBreaches.Net
P
Proofpoint News Feed
小众软件
小众软件
Vercel News
Vercel News
T
The Blog of Author Tim Ferriss
WordPress大学
WordPress大学
雷峰网
雷峰网
G
Google Developers Blog

云风的 BLOG

云风的 BLOG: 暑假的英语补习 云风的 BLOG: 银河竞逐的乐趣和策略 云风的 BLOG: 对抗系统的桌游 云风的 BLOG: 高尿酸血症确诊 云风的 BLOG: 小孩的英语辅导 云风的 BLOG: 从猎户座之王到群星 云风的 BLOG: 对基本有序的序列排序算法 云风的 BLOG: 缺氧和异星工厂的比较 云风的 BLOG: 一个简单的缺氧地热模块 云风的 BLOG: 我对《缺氧》的游戏理解 云风的 BLOG: 除法的意义 云风的 BLOG: soluna 外挂 C 模块 Star Trek : Captain's Chair 初体验 云风的 BLOG: Star Trek : Captain's Chair 初体验 用 AI 辅助读书 云风的 BLOG: 用 AI 辅助读书 日常锻炼的一些记录 云风的 BLOG: 日常锻炼的一些记录 介绍几款单人桌游 云风的 BLOG: 介绍几款单人桌游 和 AI 聊游戏设计 云风的 BLOG: 和 AI 聊游戏设计 Skynet 升级到 Lua 5.5.0 云风的 BLOG: Skynet 升级到 Lua 5.5.0 带可可学数学 云风的 BLOG: 带可可学数学 最近玩的几款卡牌构筑类电子游戏 云风的 BLOG: 最近玩的几款卡牌构筑类电子游戏 欧陆风云5的游玩笔记 云风的 BLOG: 欧陆风云5的游玩笔记
云风的 BLOG: 用地标改进 A star 寻路的启发函数
云风 · 2026-08-09 · via 云风的 BLOG

A star 寻路算法,本质上是对 Dijkstra 算法的一种改进:即从一个端点扩展节点时不盲目的向外扩展,而是利用一个启发函数优先尝试最可能在最短路径上的邻接节点。启发函数设计的越好,每一步的估计都和正确路径一致,那么就越快。依靠启发函数的结果就能避开所有不必要的节点。

但是,启发函数的复杂度不能太高,最好是 O(1) 的。因为每一步都要调用一次,时间复杂度乘在整个运算过程中。这使得启发函数不能去探测远方的状态。通常我们用当前位置到目标点的直线距离作为启发值,这个值一定小于实际路径距离,这样才能保证按启发值得到的路径一定不会比真实路径更糟糕。但在有墙和复杂迷宫的地图中,它几乎难以起到正确的引导作用。

例如,当起点在一个房间中,目标点在东边,而房间的门在西边。采用这种启发函数,算法一定会向东尝试完几乎所有路径后,才会从西边的门出去。毕竟启发函数感知不到门的位置,房间内部的东侧距离目标点的直线距离一定更近。如果房间是密闭的那就更糟了,算法会尝试完房间内的每个位置才会停下来。


有没有什么简单的方法可以改进启发函数,让它可以识别出墙,却不增加时间复杂度呢?最简单的方法是用一个地标。

在现实里,如果一个人要从北京出发去广州某地,他肯定不会从出发点地开始用 A 星算法寻路。而是先去到广州再说,北京到广州的路径是事前就已知的。到了广州再找怎么去特定地点。广州作为一个区域比较抽象,但我们可以预算计算出到广州某距离地点(例如广州塔)的路线图。对于固定目的地,可以用 Dijkstra 算法计算出到地图每个点的最短路径图( 流图 ),全部缓存下来。这样从任意点都可以用 O(1) 查询到如何去广州塔的当前移动方向。

当目的地离地标很近且当前位置离目的地很远时(从北京出发,还没进广州),按着去地标点的预设路径走一段肯定没错。直到离目的地比较近了(已经到了广州),就没必要按预设路径(去广州塔)行进了。

问题在于怎么确定离目标点比较近了?还是计算欧氏距离。

假设当前位置是 S(北京某地) ,目标点为 E (广州某地),地标点为 L (广州塔) 。这三个点可以构成一个三角形。因为三角形的任意两条边之和大于等于第三边,所以有 SE + EL >= SL 。也就是说在估价函数中,我们判断 SE 是不是大于等于 SL - EL ,即北京某地到广州某地的直线距离是不是小于等于出发地到广州塔的已知距离减去广州塔到目的地的已知距离。如果是,说明直线距离太短了,不值得按直线方向行进,应该遵循直接计算好的去广州塔的路径行进。反之,直线路径指向的方向可能是更有效的。

再看前面的房间例子:如果起点和东边的目的地之隔着一堵墙,直线距离为 1 ,但实际路径必须先绕向西侧的墙。而如果我们在目的地附近有一个预设的地标,距离目的地路程为 2,而当前位置到地标点的路程为 10 ;那么显然,从当前位置去目的地的最短路程不可能小于 10 - 2 = 8 。因为假设目的地就在去地标点的路径上,那么我们向地标行进,在剩下路程还有 2 的时候,就能抵达终点。这已经是最短路径,如果目的地偏离了这条路径,路程只能更远。

用地标的预设路程,可以更容易的排除目的地不可达的情况:如果我们可以去到地标,而地标到目的地不可达,那么目的地就不可达;同样,如果地标到目的地可达,而我们无法去到地标,目的地也不可达。如果目的地和当前位置都可以抵达地标,路径一定是存在的。只有当前位置和目的地都无法通向地标试,可达性才是未知的。


所以,我们在估价函数中,只要利用预算计算好的地标流图,就可以 O(1) 计算出是否可以复用到地标的流图给出预设方向,或是退化成传统以直线方向给出的估价值。

我们还可以多计算几个地标,比较它们哪个更有效:SL - EL 中较小的那个,决定采用到哪个地标的预设路径。地标可以是提前计算的,也可以是在多次寻路中生成的。可以想象成,如果我们没有去过广州,那么就先以一个离广州比较近的去过的地标,比如深圳为地标导引路径,一旦抵达目的地,就把新的这个目的地广州为地标记录下来,方便后续的寻路。