- 浏览: 1088295 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (695)
- 心情日记 (14)
- AS开发工具 (12)
- 文章转载 (99)
- AIR (5)
- 问题总结 (46)
- SWF格式 (7)
- 测试总结 (10)
- 外文资料 (9)
- 算法技术 (33)
- AS3常用开源库 (43)
- 源码范例 (102)
- FLEX (72)
- FLASH 优化 (33)
- 游戏开发 (49)
- 开发技术 (11)
- 工作应用 (34)
- AS3收集 (140)
- WebBase (0)
- 开发构想 (4)
- 设计模式 (2)
- 框架和框架范例 (19)
- RED5 (3)
- java开发 (3)
- JAVA (1)
- FLASH-3D (23)
- 3D (6)
- 书籍 (10)
- 业界信息资料 (3)
- C# (1)
- JavaScript (12)
- HTML5 (6)
- Flixel (1)
- D5Power RPG网页游戏引擎 (0)
- ColorMatrixFilter - 获得相应颜色的色调 函数 (0)
- Starling (0)
最新评论
-
老顽童203:
字体
水果忍者鼠标跟随特效制作[转载] -
hairball00:
[转] 放出超多的Flash组件源代码 -
he74552775:
flash AS3 RegExp简单功能用法(转) -
hanshuai1232000:
第四点,有利也有弊,等你做了大型的aprg,你就知道了
[转]位图数据内存优化 -
yangfantao:
太感谢
[转] 放出超多的Flash组件源代码
链接:http://godorz.info/2009/11/heuristics-2/
栅格地图的启发函数
在栅格上,有很多著名的启发函数可以使用.
曼哈顿距离
标准的启发函数正是曼哈顿距离.不妨看一下你的耗散函数,假设从一个栅格移动到相邻的栅格上的最小代价D.因此,在我的游戏中,启发信息是D倍的曼哈顿距离.
h(n) = D * (abs(n.x-goal.x) + abs(n.y-goal.y))
你应该使用符合你的耗散函数的单位来衡量.
(注:上面的图像中,启发函数可以找到好几条最优路径(下文称之为平局).)
对角线距离
如果你的地图允许对角线移动,那么你需要另外一个启发函数.在直角坐标中,(0,4)到(4,0)的曼哈顿距离是8*D.然而,你本可以简单的将点从(0,4)按东南方向移动至(4,0),所以启发信息应该是4*D.这个函数处理对角线问题,假定直线移动和对角线移动一个栅格的代价都是D:
h(n) = D * max(abs(n.x-goal.x), abs(n.y-goal.y))
如果对角线移动一个栅格的代价并不是D,而是类似于D2=sqrt(2)*D,那么上面的启发函数对你而言又是错误的了.你可以使用一个更为复杂的启发函数代替它.
h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
这里我们计算 h_diagonal(n) = 沿着对角线移动的步数, h_straight(n) = 曼哈顿距离,你可以通过考虑所有的对角线移动的步数(每步耗散D2)以及剩下的直线移动的步数(每步耗散D)将这两者结合在一起.
欧几里得距离
如果你的单元可以往任意方向移动(而不是沿着栅格的方向移动),那么你应该使用直线距离:
h(n) = D * sqrt((n.x-goal.x)^2 + (n.y-goal.y)^2)
然而,在这种情况下,由于耗散函数g与启发函数f并不匹配,因此这时A*算法是有问题的.因为欧几里得距离比起曼哈顿距离和对角线距离都更短,你得到的将仍然是最优路径,但A*算法运行时间将更长:
平方的欧几里得距离
在好几个A*算法的网页上,我都看见在欧几里得距离关于避免计算量巨大的开方的计算,方法仅仅是对欧几里得距离做平方.
h(n) = D * ((n.x-goal.x)^2 + (n.y-goal.y)^2)
Do not do this!这绝对会导致g和h的比例的问题.当A*算法计算f(n)=g(n)+h(n)的时候,h的平方会导致它远大于g,这意味着你得到的会是过高估计的启发函数.对于更大的h,这会使得g(n)变得无足轻重了,此时A*算法退化成宽度优先搜索.
打破平局
在某些地图中,存在着相同耗散值的路径(Arthur1989注:下文中一律称为平局).比如说,在没有凹凸的平原中,使用栅格将会得到许多路径,他们长度是一样的.A*也许会遍历所有的拥有一样的f值的路径,而不是仅仅遍历一条.(如果你的地图中有很多这样的区域,比起A*算法,对于每个栅格的搜索有其他更好的技巧.)
f值相同导致的平局
为了解决这个问题,我们要么可以调整g,要么可以调整h.相对来说,调整h会更加容易.平局的打破对于每个结点的影响必须是确定的(即:它不应该是一个随机数),而且它必须使得每个结点的f值互异.因为A*算法(OPEN表)按结点的f值大小排序,让每个结点的f值互异也就是说,对于有着”相同的”f值的结点,仅有一个会被扩展.
一种打破平局的方法是,稍微的改变h的(单位).如果我们让h的单位减小,(那么h将变大),随着A*算法向目标结点扩展,f值将会增加.不幸的是,这意味着A*算法更偏向于扩展离起始结点较近的结点,而不是扩展离目标结点较近的结点.所以,我们可以将h的单位稍微增大一点(即使是0.1%),此时,A*算法将扩展目标结点旁边的结点.
heuristic *= (1.0 + p)
因子p的选择应该使得 p<(每走一步的最小代价)/(路径的期望最大值).假设你并不希望路径的步数超过1000,你可以将p设定为1/1000.打破平局的微小改变的结果是,A*算法扩展的结点远比原先的算法要少:
在启发信息中改变h或者g的比例
当存在障碍物时,A*算法还是需要找到一条绕过障碍物的路径,但请注意,当绕过障碍物之后,A*算法扩展很少结点:
Steven van Dijk 提议了一种更为直接的方法,即把h传递给比较函数.当结点的f值是相同的时候,比较函数可以通过h值判定结点优先级来打破平局.
另外一种打破平局的方法是计算坐标(二维地图中,结点的位置即为笛卡尔坐标)的哈希值,以此来调整启发函数.比起上述调整h的方法,它可以打乱更多的平局.对提出建议的 Cris Fuhrman 致敬.
还有一种不同的打破平局的方法是,偏向于离从起始结点到目标结点的直线较近的路径.
dx1 = current.x - goal.x
dy1 = current.y - goal.y
dx2 = start.x - goal.x
dy2 = start.y - goal.y
cross = abs(dx1*dy2 - dx2*dy1)
heuristic += cross*0.001
上面的代码计算了起始结点到目标结点的向量和当前结点到目标结点的向量的内积.当这些向量不在一队上的时候,内积会变得很大.结果是A*算法稍微的偏向于扩展分布在从起始结点到目标结点的直线附近的结点.当步存在障碍物的时候,A*算法不仅可以扩展更少的结点,它得到的路径看起来也很漂亮.
启发函数中考虑了内积,生成很漂亮的路径
然而,正如上面提过的,当存在障碍物时,A*算法得到的路径看起来会有点奇怪.(注意:路径仍然是最优的)
为了交互地看出这种打破平局的方法带来的效率的提升,你可以查看James Macgill写的A* applet [如果该网址已经不在了,你可以试试 这个镜像].使用”Clear”命令来清空地图,然后在地图的两个角落选中两个结点.当你使用”经典的A*算法”是,你会看见不同结点拥有相同f值的影响.当你使用”Fudge”命令时,你可以看到上面在启发函数中使用内积信息带来的不同.
还有一种打破平局的方法是仔细的构造你的A*算法的优先级队列,它插入一个启发函数值为f的新结点,新结点比原先队列中存在的启发函数值为f的旧结点总是获得更好(坏)的排名.
也许你还可以读读AlphA* algorithm,虽然该算法打破平局的方法更为复杂,但它仍能确保得到的路径是最优的.AlphA*算法是可适应的,而且它应该比上面提到的两种打破平局的方法表现得要更好.但是,后者更为容易实现,因此你可以从后者开始尝试,当需要算法更快时才使用AlphA*算法.
寻找一个区域
如果你想要寻找任何接近于目标结点的区域,你可以构造一个启发函数h’(x),h’(x)是h1(x),h2(x),h3(x),…中的最小值,其中,h1,h2,h3是对于每个临近结点的区域的启发信息.然而,一种更快的方法是,让A*算法查找目标区域的中心结点.
栅格地图的启发函数
在栅格上,有很多著名的启发函数可以使用.
曼哈顿距离
标准的启发函数正是曼哈顿距离.不妨看一下你的耗散函数,假设从一个栅格移动到相邻的栅格上的最小代价D.因此,在我的游戏中,启发信息是D倍的曼哈顿距离.
h(n) = D * (abs(n.x-goal.x) + abs(n.y-goal.y))
你应该使用符合你的耗散函数的单位来衡量.
(注:上面的图像中,启发函数可以找到好几条最优路径(下文称之为平局).)
对角线距离
如果你的地图允许对角线移动,那么你需要另外一个启发函数.在直角坐标中,(0,4)到(4,0)的曼哈顿距离是8*D.然而,你本可以简单的将点从(0,4)按东南方向移动至(4,0),所以启发信息应该是4*D.这个函数处理对角线问题,假定直线移动和对角线移动一个栅格的代价都是D:
h(n) = D * max(abs(n.x-goal.x), abs(n.y-goal.y))
如果对角线移动一个栅格的代价并不是D,而是类似于D2=sqrt(2)*D,那么上面的启发函数对你而言又是错误的了.你可以使用一个更为复杂的启发函数代替它.
h_diagonal(n) = min(abs(n.x-goal.x), abs(n.y-goal.y))
h_straight(n) = (abs(n.x-goal.x) + abs(n.y-goal.y))
h(n) = D2 * h_diagonal(n) + D * (h_straight(n) - 2*h_diagonal(n)))
这里我们计算 h_diagonal(n) = 沿着对角线移动的步数, h_straight(n) = 曼哈顿距离,你可以通过考虑所有的对角线移动的步数(每步耗散D2)以及剩下的直线移动的步数(每步耗散D)将这两者结合在一起.
欧几里得距离
如果你的单元可以往任意方向移动(而不是沿着栅格的方向移动),那么你应该使用直线距离:
h(n) = D * sqrt((n.x-goal.x)^2 + (n.y-goal.y)^2)
然而,在这种情况下,由于耗散函数g与启发函数f并不匹配,因此这时A*算法是有问题的.因为欧几里得距离比起曼哈顿距离和对角线距离都更短,你得到的将仍然是最优路径,但A*算法运行时间将更长:
平方的欧几里得距离
在好几个A*算法的网页上,我都看见在欧几里得距离关于避免计算量巨大的开方的计算,方法仅仅是对欧几里得距离做平方.
h(n) = D * ((n.x-goal.x)^2 + (n.y-goal.y)^2)
Do not do this!这绝对会导致g和h的比例的问题.当A*算法计算f(n)=g(n)+h(n)的时候,h的平方会导致它远大于g,这意味着你得到的会是过高估计的启发函数.对于更大的h,这会使得g(n)变得无足轻重了,此时A*算法退化成宽度优先搜索.
打破平局
在某些地图中,存在着相同耗散值的路径(Arthur1989注:下文中一律称为平局).比如说,在没有凹凸的平原中,使用栅格将会得到许多路径,他们长度是一样的.A*也许会遍历所有的拥有一样的f值的路径,而不是仅仅遍历一条.(如果你的地图中有很多这样的区域,比起A*算法,对于每个栅格的搜索有其他更好的技巧.)
f值相同导致的平局
为了解决这个问题,我们要么可以调整g,要么可以调整h.相对来说,调整h会更加容易.平局的打破对于每个结点的影响必须是确定的(即:它不应该是一个随机数),而且它必须使得每个结点的f值互异.因为A*算法(OPEN表)按结点的f值大小排序,让每个结点的f值互异也就是说,对于有着”相同的”f值的结点,仅有一个会被扩展.
一种打破平局的方法是,稍微的改变h的(单位).如果我们让h的单位减小,(那么h将变大),随着A*算法向目标结点扩展,f值将会增加.不幸的是,这意味着A*算法更偏向于扩展离起始结点较近的结点,而不是扩展离目标结点较近的结点.所以,我们可以将h的单位稍微增大一点(即使是0.1%),此时,A*算法将扩展目标结点旁边的结点.
heuristic *= (1.0 + p)
因子p的选择应该使得 p<(每走一步的最小代价)/(路径的期望最大值).假设你并不希望路径的步数超过1000,你可以将p设定为1/1000.打破平局的微小改变的结果是,A*算法扩展的结点远比原先的算法要少:
在启发信息中改变h或者g的比例
当存在障碍物时,A*算法还是需要找到一条绕过障碍物的路径,但请注意,当绕过障碍物之后,A*算法扩展很少结点:
Steven van Dijk 提议了一种更为直接的方法,即把h传递给比较函数.当结点的f值是相同的时候,比较函数可以通过h值判定结点优先级来打破平局.
另外一种打破平局的方法是计算坐标(二维地图中,结点的位置即为笛卡尔坐标)的哈希值,以此来调整启发函数.比起上述调整h的方法,它可以打乱更多的平局.对提出建议的 Cris Fuhrman 致敬.
还有一种不同的打破平局的方法是,偏向于离从起始结点到目标结点的直线较近的路径.
dx1 = current.x - goal.x
dy1 = current.y - goal.y
dx2 = start.x - goal.x
dy2 = start.y - goal.y
cross = abs(dx1*dy2 - dx2*dy1)
heuristic += cross*0.001
上面的代码计算了起始结点到目标结点的向量和当前结点到目标结点的向量的内积.当这些向量不在一队上的时候,内积会变得很大.结果是A*算法稍微的偏向于扩展分布在从起始结点到目标结点的直线附近的结点.当步存在障碍物的时候,A*算法不仅可以扩展更少的结点,它得到的路径看起来也很漂亮.
启发函数中考虑了内积,生成很漂亮的路径
然而,正如上面提过的,当存在障碍物时,A*算法得到的路径看起来会有点奇怪.(注意:路径仍然是最优的)
为了交互地看出这种打破平局的方法带来的效率的提升,你可以查看James Macgill写的A* applet [如果该网址已经不在了,你可以试试 这个镜像].使用”Clear”命令来清空地图,然后在地图的两个角落选中两个结点.当你使用”经典的A*算法”是,你会看见不同结点拥有相同f值的影响.当你使用”Fudge”命令时,你可以看到上面在启发函数中使用内积信息带来的不同.
还有一种打破平局的方法是仔细的构造你的A*算法的优先级队列,它插入一个启发函数值为f的新结点,新结点比原先队列中存在的启发函数值为f的旧结点总是获得更好(坏)的排名.
也许你还可以读读AlphA* algorithm,虽然该算法打破平局的方法更为复杂,但它仍能确保得到的路径是最优的.AlphA*算法是可适应的,而且它应该比上面提到的两种打破平局的方法表现得要更好.但是,后者更为容易实现,因此你可以从后者开始尝试,当需要算法更快时才使用AlphA*算法.
寻找一个区域
如果你想要寻找任何接近于目标结点的区域,你可以构造一个启发函数h’(x),h’(x)是h1(x),h2(x),h3(x),…中的最小值,其中,h1,h2,h3是对于每个临近结点的区域的启发信息.然而,一种更快的方法是,让A*算法查找目标区域的中心结点.
发表评论
-
水果忍者鼠标跟随特效制作[转载]
2012-03-01 16:06 2457实现这效果其实比较简单,主要是思路~! package ... -
[转]三次贝尔曲线
2011-11-10 01:09 1932http://bbs.9ria.com/viewt ... -
轻量级Eval库Grak轻量级Eval库Grak
2011-09-22 03:07 0轻量级Eval库Grak -
[转]AS3与数据结构
2011-09-14 01:08 0http://www.nshen.net/dataSt ... -
井字棋算法
2011-08-18 15:04 0井字棋算法井字棋算法 -
[转 自己改的一个滚动条类,理论上什么都能“滚”
2011-08-11 23:14 0http://bbs.9ria.com/viewthread. ... -
[转] 关于一段时间内鼠标没有移动,执行某函数
2011-08-10 00:22 0http://bbs.9ria.com/viewthread. ... -
很好的FLEX表情聊天界面
2011-08-09 02:06 0很好的FLEX表情聊天界面 -
Flash版《植物大战僵尸》源码
2011-08-09 01:34 0本帖最后由 IJUST 于 2 ... -
愤怒的小鸟 BOX2D FLASH
2011-08-09 01:27 0姊妹篇:Flash版《植物大战僵尸》源码今年就要大四啦,放暑假 ... -
[转]如何计算线段和圆的交点
2011-08-09 00:53 0http://www.thecodeway.com/b ... -
[转] 45度地图坐标转换
2011-07-30 02:41 0昨天有朋友问我 45度地图中关于鼠标点击如果进行坐标转化 ... -
[转]一个Collision类,其中的block方法可以实现两个物体之间的碰撞检测。
2011-07-30 02:35 1401第二个是书中的源代码给出了一个Collision类,其中 ... -
AS3的一些优化计算方法
2011-07-06 12:56 0http://www.cnitblog.com/flashli ... -
[转]AS3类:CRC32校验类
2011-07-06 12:54 2611http://www.cnitblog.com/flashli ... -
基于哈希表数据源的A星寻路算法 - [as 3.0]
2011-06-16 17:03 0在这贴的代码是为了有需要的人学习而不是 提供源码给别人用的 ... -
计算几何算法概览
2011-06-14 17:28 2124计算几何算法概览 一、引言 ... -
[演示] 判断点是否处于三角形内的算法分析
2011-06-14 17:26 3313http://bbs.wow8.org/thread-9429 ... -
判断点在直线的哪一侧
2011-06-14 17:04 0判断点在直线的哪一侧 2.2.1下面开始程序的设计: ... -
[转]动画中坐标旋转公式的原理
2011-05-25 23:30 1500有一定的其它语言编程基础,所以学习新语言还是比较快的。正在进军 ...
相关推荐
在`solvePuzzleAStarSearch.cpp`和`solvePuzzleAStarSearch.h`这两个文件中,很可能包含了A*算法的实现细节,如状态表示、启发式函数定义、节点拓展规则以及优先队列的数据结构等。这些代码将演示如何使用C++来处理...
2. **启发式函数**:选择合适的启发式函数,如曼哈顿距离或欧几里得距离,用于估计从当前节点到目标节点的剩余成本。启发式函数必须是无偏的,即它给出的估计值永远不会超过实际成本。 3. **代价计算**:为每个节点...
描述中提到"用python语言实现",意味着我们将使用Python编程语言来编写A*算法的代码,并且该实现已经在一个包含400个节点的数据集上进行了测试。这暗示了我们将涉及到数据结构、图的表示以及Python的编程技巧。 **A...
A*算法是一种在图形搜索问题中寻找最优路径的启发式搜索算法,由Peter Hart、Nils Nilsson和Bertram Raphael在1968年提出。它的主要目标是在有限的计算时间内找到从起点到终点的最短路径,特别适用于静态路网中的...
【A*算法详解】 A*算法是人工智能领域中用于寻找最短路径的一种高效搜索策略,尤其在路径规划问题中有着广泛的应用。...在实际应用中,A*算法需要根据具体的环境和问题特点,设计适当的启发式函数,以达到最优性能。
在提供的文档"rr.doc.doc"和"A算法"中,可能会详细解释A*算法的原理,包括如何构建搜索树、如何计算启发式函数、如何维护开放列表和关闭列表等。同时,可能会通过实例演示如何应用A*算法来解决具体的N码难题,展示...
同时,优化A*算法的方法包括使用二进制堆优化开放列表、动态调整启发式函数精度、以及使用启发式函数缓存以减少重复计算。 总的来说,理解和实现A*算法需要对图论、数据结构和搜索算法有深入的理解。在Java和C++中...
A*算法的核心思想是在搜索过程中结合了启发式信息,即一个从当前节点到目标节点的估计代价,通常用一个启发式函数(如曼哈顿距离或欧几里得距离)来表示。这个算法使用了一个开放节点集和关闭节点集,通过评估每个...
A*算法的核心在于引入了启发式函数,使得搜索更加高效,能够在大量可能的路径中找到最优解。 在Python中实现A*算法,首先需要理解其基本步骤: 1. **初始化**:创建一个空的开放列表和关闭列表。开放列表用于存放待...
2. **动态调整启发式**:根据搜索过程中的信息更新启发式函数,如使用A-D*算法,当路径发生变化时,能够快速重新规划。 3. **记忆化搜索**:利用已搜索节点的信息,避免重复计算,提高效率。 4. **开放列表排序...
2. **启发式函数**:定义用于估计从当前节点到目标节点代价的函数,如曼哈顿距离或欧几里得距离。 3. **双向搜索**:分别从起点和终点开始,使用优先队列(如二叉堆)存储待处理节点,并按照f值进行排序。 4. **节点...
A*算法是一种在图形搜索中广泛应用的启发式搜索策略,其目标是找到从起点到终点的最短路径。在这个特定的场景中,A*算法被用于解决旅行商问题(Traveling Salesman Problem, TSP)。TSP是一个经典的组合优化问题,...
A星(A*)算法是一种在图形搜索中广泛使用的路径规划算法,它的主要目标是找到从起点到终点的最短路径。A*算法结合了Dijkstra算法的全局最优性和最佳优先搜索的效率,通过引入启发式函数来指导搜索,使得算法能够更...
2. **启发式函数**:设计h(n)函数,例如曼哈顿距离或欧几里得距离,以估算从当前节点到目标状态的距离。 3. **开放列表和关闭列表**:开放列表存储待处理的节点,按f(n)值排序;关闭列表存储已处理过的节点,避免...
A*算法的启发函数是f(n)=g(n)+h(n),其中g(n)表示从起始搜索点到当前点的代价,h(n)表示当前结点到目标结点的估值。h(n)的设计是A*算法的关键,h(n)的设计好坏直接影响着A*算法的效率。 A*算法的优点是可以快速地...
2. **开放列表与关闭列表**:A*算法使用两个列表来跟踪节点的状态。开放列表存储待评估的节点,它们有可能是最优路径的一部分。关闭列表存储已评估过的节点,以避免重复计算。 3. **F、G、H函数**:A*算法的核心...
2. **A*算法**:编写A*算法的实现,包括开放列表、关闭列表、启发式函数以及如何根据f(n)值选择下一个节点。 3. **吃豆人和幽灵的运动**:定义它们的移动规则,如四向移动、碰撞检测和转向逻辑。 4. **游戏循环**:...
3. **启发式函数**:`h(n)`的计算是A*算法的关键,它需要提供一个估计目标距离的近似值。常见的启发式函数有曼哈顿距离、欧几里得距离、切比雪夫距离等。优化版可能对启发式函数进行了调整,使其更准确或计算更快。 ...
2. **启发式函数(Heuristic Function)**:启发式函数是A*算法的核心部分,它提供了一种估计剩余代价的方法。常见的启发式函数有曼哈顿距离、欧几里得距离和切比雪夫距离等。在C#中,你可以根据实际问题的特性来...
入口坐标和出口坐标分别为(startx,starty)和(endx,eny),每一个坐标点有两种可能:0或1,其中0表示该位置允许通过,1表示该位置不允许通过。以寻路问题为例实现A*算法的求解程序,设计两种不同的估价函数。