A*寻路算法中的启发式函数:曼哈顿距离与欧几里得距离详解

1. A*算法基础

A*算法是一种广泛应用于游戏开发和机器人导航的启发式搜索算法。其核心公式为:

1
f(n) = g(n) + h(n)

其中:

  • f(n) 是节点n的总评价函数
  • g(n) 是从起点到节点n的实际代价
  • h(n) 是从节点n到目标的估计代价(启发式函数)

启发式函数的选择直接影响A算法的效率和结果路径的质量。最常用的两种启发式函数是曼哈顿距离*欧几里得距离

2. 曼哈顿距离 (Manhattan Distance)

2.1 定义与计算

曼哈顿距离又称为”城市街区距离”,计算公式为:

1
h = |x2 - x1| + |y2 - y1|

在三维空间中,公式扩展为:

1
h = |x2 - x1| + |y2 - y1| + |z2 - z1|

2.2 特点分析

优点:

  • 计算简单高效,不涉及复杂数学运算
  • 在只允许水平和垂直移动的网格中提供精确估计
  • 保证可接受性(不会高估实际成本)

限制:

  • 在允许对角线移动的网格中会高估路径长度
  • 不适用于连续空间或自由角度移动的场景

2.3 适用场景

  • 四方向移动的网格地图(如:经典的迷宫问题)
  • 城市街道导航(城市街道通常呈网格状)
  • 类似《吃豆人》的游戏,角色只能沿网格线移动
  • 棋类游戏如国际象棋中车(Rook)的移动

2.4 代码实现

1
2
3
4
float ManhattanDistance(Node a, Node b)
{
return Mathf.Abs(a.x - b.x) + Mathf.Abs(a.y - b.y);
}

3. 欧几里得距离 (Euclidean Distance)

3.1 定义与计算

欧几里得距离是两点间的直线距离,计算公式为:

1
h = √((x2 - x1)² + (y2 - y1)²)

在三维空间中,公式扩展为:

1
h = √((x2 - x1)² + (y2 - y1)² + (z2 - z1)²)

3.2 特点分析

优点:

  • 提供两点间最短路径的精确估计
  • 在任意角度移动的场景中表现良好
  • 对于连续空间寻路非常适合

限制:

  • 计算开销较大(涉及平方和平方根运算)
  • 在只允许正交移动的网格中会低估实际路径长度

3.3 适用场景

  • 开放世界游戏中的自由移动
  • 3D空间的导航
  • 允许全方向移动的RTS游戏
  • 无人机或机器人的路径规划

3.4 代码实现

1
2
3
4
5
6
7
float EuclideanDistance(Node a, Node b)
{
return Mathf.Sqrt(
(a.x - b.x) * (a.x - b.x) +
(a.y - b.y) * (a.y - b.y)
);
}

4. 两种距离函数的比较

4.1 计算效率

距离函数 计算复杂度 相对性能
曼哈顿距离 O(1),仅包含基本运算 更快
欧几里得距离 O(1),但包含平方根运算 较慢

4.2 路径特性比较

距离函数 生成路径特性 搜索扩展形状
曼哈顿距离 倾向于生成”之”字形路径 菱形扩展
欧几里得距离 倾向于生成更直接的路径 圆形扩展

4.3 视觉对比

当使用曼哈顿距离时,A*算法的搜索空间类似于一个菱形,从起点向外扩展

当使用欧几里得距离时,搜索空间更像一个圆形

5. 实际应用中的选择策略

5.1 基于移动模型选择

  • 仅允许正交移动(上下左右):优先选择曼哈顿距离
  • 允许对角线移动:考虑使用对角线距离(或欧几里得距离)
  • 自由角度移动:使用欧几里得距离

5.2 基于性能需求选择

  • 对性能要求极高:考虑使用曼哈顿距离或欧几里得距离平方(避免平方根运算)
  • 需要最优路径:选择与移动模型匹配的距离函数

5.3 混合策略

在某些情况下,可以采用混合策略:

  • 在开放区域使用欧几里得距离
  • 在网格约束区域使用曼哈顿距离
  • 根据地形特性动态切换启发式函数

6. 代码优化技巧

6.1 欧几里得距离的优化

对于仅需比较距离大小而非精确值的场景,可以使用欧几里得距离平方来避免开销较大的平方根运算:

1
2
3
4
float EuclideanDistanceSquared(Node a, Node b)
{
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}

6.2 预计算技巧

对于静态地图,可以预计算起点到各点的距离,减少运行时计算:

1
2
3
4
5
6
7
8
// 预计算阶段
void PrecomputeHeuristics(Node target)
{
foreach(Node node in allNodes)
{
node.heuristicToTarget = ManhattanDistance(node, target);
}
}

7. 综合案例分析

7.1 案例:网格地图中的寻路

考虑一个10x10的网格地图,起点坐标(1,1),终点坐标(8,8):

  • 使用曼哈顿距离:|8-1| + |8-1| = 14
  • 使用欧几里得距离:√((8-1)² + (8-1)²) ≈ 9.9

如果网格只允许上下左右移动,实际最短路径长度为14,曼哈顿距离提供了精确估计。
如果允许对角线移动,最短路径长度为7(沿对角线直接移动),欧几里得距离的估计更接近。

7.2 案例:性能与精确度的权衡

在一个大型RTS游戏中,需要同时处理数百个单位的寻路:

  • 对于远距离初步规划:使用曼哈顿距离快速规划大致路径
  • 对于精细导航和障碍物规避:切换到欧几里得距离
  • 在性能瓶颈场景:考虑使用欧几里得距离平方作为近似值

8. 结论

曼哈顿距离和欧几里得距离是A*算法中两种最基础且最常用的启发式函数。选择合适的启发式函数应基于:

  1. 移动规则:考虑游戏或应用中允许的移动方式
  2. 计算效率:评估性能需求与路径质量的平衡
  3. 地图特性:分析环境的特点和约束

掌握这两种距离函数的特点和应用场景,能够帮助开发者更有效地实现A*寻路算法,为游戏和应用提供高效、自然的路径规划解决方案。