启发式
Posted xuuold
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了启发式相关的知识,希望对你有一定的参考价值。
启发式函数h(n)
告诉A * 估计从任何顶点n
到目标的最小成本。选择一个好的启发式函数孙很重要的事情。
用启发式算法的A*
启发式可用于控制A *的行为。
- 在一个极端,如果
h(n)
是0,那么只g(n)
起作用,A* 变成 Dijkstra算法,保证找到最短路径。 - 如果
h(n)
总是低于(或等于)从n
目标移动到目标的成本,则 A* 保证找到最短路径。h(n) 越低,节点 A* 扩展越多,使其变慢。 - 如果
h(n)
完全等于从n
目标移动到目标的成本,那么 A* 将只遵循最佳路径并且永远不会扩展其他任何东西,使其非常快。虽然你不能在所有情况下都能实现这一点,但你可以在某些特殊情况下做到这一点。很高兴知道,鉴于完美的信息,A *将表现得非常完美。 - 如果
h(n)
有时大于从n
目标移动到目标的成本,那么 A* 不能保证找到最短路径,但它可以更快地运行。 - 在另一个极端,如果
h(n)
相对于 g(n) 非常高,那么h(n) 只
起一个作用,A *变成贪婪的最佳先搜索。
注意:
从技术上讲,如果启发式算法低估了实际成本,则应简单地将 A* 算法称为 A。但是,我将继续将其称为 A*,因为实现是相同的,并且游戏编程社区不区分 A 和 A*。
所以我们有这样一个有趣的情况,我们可以决定我们想要从 A* 中获得什么。
在恰当的位置,我们会很快得到最短的路径。
如果我们设定地太低,那么我们将继续获得最短的路径,但它会慢下来。
如果我们设定地太高,那么我们放弃最短路径,但 A* 会跑得更快。
在游戏中,A* 的这个属性非常有用。
例如,您可能会发现在某些情况下,您宁愿拥有一条“好”路径而不是“完美”路径。
要在 g(n)
和 h(n)之间寻找平衡性,您可以修改其中任何一个。
速度还是准确度?
A* 基于启发式和成本函数改变其行为的能力在游戏中非常有用。
可以利用速度和准确度之间的权衡来加快游戏速度。
对于大多数的游戏,你不真正需要的最好的两个点之间的路径。
你需要一些接近的东西。你需要什么可能取决于游戏中发生了什么,或者计算机的速度有多快。
假设你的游戏有两种类型的地形,Flat 和 Mountain,平地的移动成本是1,山的移动成本是3。
A* 沿着平坦的土地搜索 3 次,和山地的 1 次是相同的开销。这是因为它可能在平坦的地形上有一条环绕山脉的路径。
您可以使用 1.5 作为两个平地之间的启发式距离来加速 A* 的搜索。这样的话,A* 将比较 3 和 1.5,它看起来不会像比较 3 和 1 那样糟糕。
这样的话,山地看起来并非那样令人不满意(开销过大),所以它不会花费太多时间试图找到其他的解决方法。
或者,您可以通过减少搜索山脉周围路径的数量来加快 A* 的搜索速度 - 即告诉 A* 山上的移动费用是 2 而不是 3。
这样的话,沿平坦地形搜索 2 次,和沿着山区地形 1 次的开销相同。
这两种方法都放弃了最理想的路径来更快地获得结果。
速度和准确度之间的选择不必是静态的。
您可以根据 CPU 速度,进入寻路的时间比例,地图上的单位数量,单位的重要性,组的大小,难度级别或任何其他因素动态选择。
使权衡动态的一种方法是构建一个启发式函数,假设行进一个网格空间的最小成本为1,然后构建一个可扩展的成本函数:
如果 alpha
为 0,则修改的成本函数将始终为 1。
这样设置的话,会完全忽略地形成本,并且 A* 在网格中会简单地进行 可通过/不可通过 的判断。
如果 alpha
为 1,则将使用原始成本函数,您将获得 A* 的全部的优点。
您可以将 alpha
在两者之间进行调整。
您也应该考虑在启发式返回的绝对最低成本和预期的最低成本之间进行权衡。
例如,如果您的大部分地图都是草地,移动成本为 2,但地图上的某些地方的道路的移动成本为 1,那么您可能会考虑到启发式假设没有道路的情况,然后返回 2 * distance
。
速度和准确度之间的选择不一定是全局的。
在地图某些区域的准确性可能很重要,我们可以根据这些来动态选择一些内容。
例如,我们在靠近某些位置时,需要一条最佳路径。
基于这个假设,在这个位置附近时,我们可能需要重新计算路径。
而远离这个位置时,为什么要对路径的准确性做要求呢?
在地图的安全区域拥有最短的路径也许并不是那么重要,但是当偷偷溜过一个敌人的村庄时,安全和快速是必不可少的。
衡量单位
A* 计算 f(n) = g(n) + h(n)
。
要添加两个值,这两个值必须处于相同的衡量单位。
如果 g(n)
以小时为单位而 h(n)
以米为单位进行测量,则 A* 将考虑 g
或 h
过多或过少,并且您要么不会获得良好的路径,要么 A* 将会运行得比预期要慢。
具体的启发式
如果您的启发式方法与最佳路径上的距离完全相等,您将看到 A* 扩展的节点非常少,如下一节的图表所示。
A* 算法内部发生的事情是它在每个节点上计算 f(n) = g(n) + h(n)。
当 h(n)
完全匹配 g(n)时
,f(n)的值
不沿路径更改。
不在正确路径上的所有节点,将会比在正确路径上的节点,具有值更高的 f。
由于 A* 在考虑较低值 f 节点之前不考虑 f 值较高的节点,因此它永远不会偏离最短路径。
预先计算
构造具体的启发式的一种方法是预先计算每两个点之间的最短路径的长度。
这对于大多数游戏地图来说是不可行的。但是,有一些方法来近似这种启发式:
- 使用包含数个小网格的大网格。预先计算任何一对大网格位置之间的最短路径。
- 预先计算任何一对路径点之间的最短路径。这是使用大网格方法的一种形式。
然后添加一个启发式算法 h‘,估算从任何位置到附近航路点的费用(如果需要,这个也可以预先计算)。
最终的启发式将是:
或者,你也可以找一个更好的,但开销更大的启发式函数,上述 w1 和 w2 分别是接近起点和目标点的路径点。
网格地图的启发式算法
在网格上,有一些众所周知的启发式函数可供使用。
使用与允许的移动匹配的距离启发式:
- 在允许4个运动方向的方格上,使用曼哈顿距离 (L1)。
- 在允许8个运动方向的正方形网格上,使用对角线距离 (L∞)。
- 在允许任何移动方向的方格上,您可能想要也可能不想要欧几里德距离 (L2)。如果A *在网格上找到路径但您不允许在网格上移动,则可能需要考虑地图的其他表示。
- 在允许6个方向移动的六边形网格上,使用适合六边形网格的曼哈顿距离。
将 [步长] 乘以 [步长的最小成本] 。
例如,如果您以米为单位测量,距离为3格,每个方格为15米,那么启发式将返回3?15= 45米。
如果你在时间上测量,距离是 3 个方格,每个方格需要至少 4 分钟才能穿过,然后启发式将返回 3 × 4 = 12 分钟。
启发式返回的单位(米,分钟等)应与成本函数使用的单位相匹配。
曼哈顿距离
方形网格的标准启发式是曼哈顿距离。
查看您的成本函数,令一个格子移动到相邻格子的最低成本为 D。
在简单的情况下,您可以设置 D 为 1。
对方形网格来说,您可以在4个方向上移动的启发式方法,应该是 D ? 曼哈顿距离:
需要怎么设置 D ?使用与您的成本函数匹配的衡量单位。
对于最佳路径和“允许的”启发式,将 D 设置为相邻方块之间的最低成本。
在没有障碍物,以及在移动成本 D 最小的地形上,向目标移动一步,g 增加 D,h 减少 D。
当这两个进行变化时,f ( 根据 g 和 h 变化) 将保持不变;这是启发式和成本函数衡量单位一致的表现。
您还可以放弃最佳路径,通过增加 D 或 降低 [最低和最高的边之间的开销的差值] 来使 A* 运行得更快。
(注意:上面的图片在启发式中解决了相等开销的情况。)
对角线距离
如果地图允许对角线移动,则需要使用不同的启发式方法。
(4 east, 4 north) 方向的曼哈顿距离将为 8 × D 。
但是,您可以简单地往 (4 northeast) 移动,因此启发式应该是 4 × D2,其中 D2 是对角移动的成本。
在这里,我们先计算出如果不能采取对角线时,一共会走的步数,然后减去你使用对角线的步数。
这里有 min(dx, dy) 步会走
对角线,每一步有 D2 的开销,但可以节省原本的开销,非对角线时对应的开销为 2 × D。
当 D = 1 且 D2 = 1 时,这称为切比雪夫距离(Chebyshev distance)。
当 D = 1 且 D2 = sqrt(2)时,这称为八分距离(octile distance)。
这种的另一个写法是 D * max(dx, dy) + (D2 - D) * min(dx, dy),这些都是等价的。
欧氏距离(Euclidean distance)
如果您的单位可以朝任何角度(而不是网格方向)移动,那么您应该使用直线距离:
但是,如果是这种情况,那么您可能无法直接使用 A*,因为成本函数 g 与启发式函数 h 不匹配
。
由于欧几里德距离比曼哈顿或对角线距离短,您仍然会获得最短路径,但 A* 将需要更长时间才能运行:
欧氏距离,平方
我看到几个介绍 A* 的网页,建议您使用距离的平方,从而避免欧几里德距离中开销昂贵的平方根:
不!要!这!样!做!
这肯定会遇到单位上的问题。
g 和 h 的单位要匹配,因为你将它们加在一起形成 f 。
当 A* 计算 f(n) = g(n) + h(n) 时
,距离的平方将远远高于成本 g
,你最终会得到一个高估的启发式。
对于更长的距离,这将接近 g(n),而无法对计算
f(n)产生帮助
,并且 A* 将降级为贪心的最佳优先搜索:
要尝试解决此问题,您可以缩小启发式的影响。
然而,你会遇到了相反的问题:对于较短的距离,启发的影响和 g(n) 相比,将会太小,A* 会降级为 Dijkstra算法。
以上是关于启发式的主要内容,如果未能解决你的问题,请参考以下文章