type
status
date
slug
summary
tags
category
icon
password
fullWidth
fullWidth

A*搜索算法知识梳理

1. A*算法的基本概念

A*算法是一种启发式搜索算法,它通过评估函数来决定搜索的顺序。其中:
  • 是从起点到节点的实际代价。
  • 是从节点到目标节点的估计代价(启发式函数)。
A*算法的目标是找到从起点到目标节点的最优路径,即代价最小的路径。

2. 可采纳性(Admissibility)

启发式函数必须满足可采纳性,即不能高估从节点到目标节点的实际代价;即必须小于或等于到目标节点的真实代价,即
🐈
结论:
只要启发式函数满足可采纳性(即),A*算法就能保证找到最优路径。
反证法:
假设A*算法返回了一条非最优路径,其代价
  1. 在非最优路径上,存在一个节点,使得:
      • 特别地,目标节点满足:
  1. 在最优路径上,一定存在一个不同于的节点,使得:
  1. 而A*算法按照的值从小到大扩展节点(每次从小根堆中弹出元素加入closeList);这意味着会先于被扩展。
  1. 如果被扩展,A*算法会继续从向目标节点搜索,找到最优路径;与假设矛盾。
 

3. 一致性(Consistency)

一致性是比可采纳性更强的条件。它要求对于任意节点和它的后继节点,启发式函数满足以下不等式:;其中是从节点到节点实际代价
一致性确保了启发式函数在搜索过程中不会与过去的预测相矛盾:
  • 最优性保证:一致性是可采纳性的一个更强条件。如果满足一致性,那么它必然满足可采纳性。
  • 路径代价的一致性:在搜索过程中,算法不会发现一条路径的代价比之前估计的更低;避免了算法在搜索过程中反复调整路径。
🐈
一致性与可采纳性的区别:
  • 一致性不仅要求可采纳性,还要求启发式函数满足三角不等式:;保证了启发式函数在节点扩展时是“平滑”的,避免了重复更新节点代价的情况。
  • 如果启发式函数仅满足可采纳性,A*算法仍然能找到最优路径,但可能会多次重新开放和更新某些节点的代价,导致效率降低

4.启发式函数变体(Variable)

在网格地图中,通常使用曼哈顿距离欧式距离等作为启发式函数的计算,但在中继点地图(Waypoint Graph)或GOAP(目标导向行动规划)中,的设计需要适应新的问题。
一个中继点地图示例
一个中继点地图示例
在GOAP中,的设计不再是简单的几何距离,而是需要估计当前状态与目标状态的“接近程度”;例如:
  • 如果目标是“找到武器”,为当前状态与“拥有武器”状态之间的差异。
  • 如果目标是“击败敌人”,为当前状态与“敌人被击败”状态之间的差异。

5.算法退化(Degradation)

当启发式函数始终返回0时,A*算法会退化为Dijkstra算法。因为;算法在选择下一个扩展节点时,只考虑从起点到当前节点的实际代价(Dijkstra算法就是每次选择当前已知代价最小的节点进行扩展,总代价函数实际上就是),从而A*算法失去了启发式引导的作用。

A*搜索算法通用框架

节点接口

任意类通过继承此接口,成为A*算法中的可搜索节点。
属性
属性
作用
Parent
父节点,用于回溯生成完整路径
SelfCost
移动到该节点的单步代价(如地形消耗)
GCost
从起点到该节点的累计实际代价
HCost
到终点的启发式估计代价(如直线距离)
FCost
总代价 = GCost + HCost(只读)
关键方法
  1. GetDistance(T otherNode
      • 用途:计算到目标节点的启发式估计值(如曼哈顿距离)。
      • 参数otherNode - 目标节点。
  1. GetSuccessors(object nodeMap)
      • 用途:获取所有可达的邻居节点列表。
      • 参数nodeMap - 搜索空间(如地图数据)。
      • 注意:需在此方法中设置邻居节点的 SelfCost(自身移动到邻居节点的代价)。
IAstarNode<T>接口

搜索器

实现A*搜索算法,用于在给定的搜索空间(地图)中寻找起点到终点的最优路径
泛型约束
泛型参数
约束条件
作用
T_Map
表示搜索空间(如地图)。
T_Node
IAStarNode<T_Node>IComparable<T_Node>IEquatable<T_Node>
表示搜索节点,需实现节点接口和比较接口。
核心成员
成员
类型
作用
closeList
HashSet<T_Node>
探索集,存储已探索的节点(哈希集合)。
openList
MyHeap<T_Node>
边缘集,存储待探索的节点(优先队列)。
nodeMap
T_Map
搜索空间(地图)。
关键方法
  1. FindPath(T_Node start, T_Node target, Stack<T_Node> pathRes)
      • 用途:执行 A* 搜索,生成从起点到终点的路径。
      • 参数
        • start - 起点节点。
        • target - 终点节点。
        • pathRes - 用于存储生成的路径(栈结构)。
  1. GenerateFinalPath(T_Node startNode, T_Node endNode, Stack<T_Node> pathStack)
      • 用途:从终点回溯到起点,生成完整路径。
      • 参数
        • startNode - 起点节点。
        • endNode - 终点节点。
        • pathStack - 用于存储路径的栈。
  1. UpdateTwoLists(T_Node curNode, T_Node endNode)
      • 用途:更新探索集和边缘集。
      • 参数
        • curNode - 当前节点。
        • endNode - 终点节点。
AStarSearcher<T_Map, T_Node>类

框架使用示例

节点(Node)

Node类实现了IAstarNode<Node>接口,并新增和重写了必要的方法。
  1. AddNeighbor
      • 添加邻居节点及其连接代价(边长)。
  1. GetDistance
      • 启发式函数,估计到目标节点的代价:
        • 如果直接连接,返回边代价。
        • 否则,返回最小边代价或0。
  1. GetSuccessors
      • 返回所有邻居节点,并设置其SelfCost
  1. CompareTo
      • 比较节点优先级:优先比较FCost,若相等,则再比较HCost
  1. EqualsGetHashCode
      • 判断节点是否相等,基于Id

图(Graph)

Graph类用于表示有向图,支持节点的添加、边的连接以及节点的查询。
  1. AddNode
      • 添加节点:如果节点Id不存在,则创建新节点并加入字典。
  1. AddEdge
      • 添加有向边:从fromId节点到toId节点,设置连接代价。
  1. GetNode
      • 获取节点:根据Id返回对应节点。

初始化和搜索

下面是一个使用示例:
  1. 创建有向图,并添加节点,指定节点的连接关系(添加有向边)
  1. 设置起点和终点
  1. 初始化GCost,由于不知道可达性,起点之外的其他节点GCost设置为无穷大
  1. 调用搜索器的FindPath方法执行搜索
示例输出:
 
自制Python任务调度模块-MySchedule游戏算法-Floyd搜索算法知识梳理和通用框架
Loading...
Latest posts
游戏算法-Floyd搜索算法知识梳理和通用框架
2025-4-2
游戏算法-A*搜索算法知识梳理和通用框架
2025-4-2
游戏AI行为决策-目标导向行为规划(GOAP)通用框架
2025-3-23
自制Python任务调度模块-MySchedule
2025-3-20
学习笔记:23种设计模式
2025-3-19
学习笔记:计算机网络(自顶向下方法)课程笔记
2025-3-15