1、A算法A*算法A*算法思想(启发函数法)A*在游戏设计中有它很典型的用法,是人工智能在游戏中的代表。A*算法属于一种启发式搜索。它扩展结点的次序类似于广度优先搜索,但不同的是每生成一个子结点需要计算估价函数F,以估算起始结点到该结点的代价及它到达目标结点的代价的和;每当扩展结点时,总是在所有待扩展结点中选择具有最小F值的结点作为扩展对象,以便使搜索尽量沿最有希望的方向进行。因此,A*算法只要求产生问题的全部状态空间的部分结点,就可以求解问题了,搜索效率较高。确定估价函数方法通常是:搜索到该结点的深度+ 距离目标最近的程度。一、何谓启发式搜索算法: 在说它之前先提提状态空间搜索。状态空间搜索,如
2、果按专业点的说 法就是将问题求解过程表现为从 初始状态到目标状态寻找这个路径的 过程。通俗点说,就是在解一个问题时,找到一条解题的过程可以从求解的开始到问题的结果(好象并不通俗哦)。由于求解问题的过程 中分枝有很多,主要是求解过程中求 解条件的不确定性,不完备性造 成的,使得求解的路径很多这就构成了一个图,我们说这个图就是状 态空 间。问题的求解实际上就是在这个图中找到一条路径可以从开始 到结果。这个寻找的过程就是状态空间搜索。 常用的状态空间搜索有深度优先和广度优先。广度优先是从初始状态一层一层向下找,直到找到目标 为止。深度优先是按照一定的顺序前 查找完一个分支,再查找另一个分支,以至找到
3、目标为止。这两种算 法在数据结构书中都有描述,可以参看这些书得到更详细的解释。 前面说的广度和深度优先搜索有一个很大的缺陷就是他们都是在一个 给定的状态空间中穷举。这在状 态空间不大的情况下是很合适的算法 ,可是当状态空间十分大,且不预测的情况下就不可取了。他的效率 实在太低,甚至不可完成。在这里就要用到启发式搜索了。 启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估, 得到最好的位置,再从这个位置 进行搜索直到目标。这样可以省略 大量无畏的搜索路径,提到了效率。在启发式搜索中,对位置的估价 是十分重要的。采用了不同的估价可以有不同的效果。我们先看看 估价是如何表示的。 启发中的估价
4、是用估价函数表示的,如: f(n) = g(n) + h(n) 其中f(n) 是节点n的估价函数,g(n)实在状态空间中从初始节点到 n节点的实际代价,h(n)是从n到目 标节点最佳路径的估计代价。在 这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。如果说 详细点,g(n)代表了搜索的广度的优先趋势。但是当h(n) g(n) 时,可以省略g(n),而提高效率。二、初识A*算法: 启发式搜索其实有很多的算法,比如:局部择优搜索法、最好优先搜索 法等等。当然A*也是。这些算法 都使用了启发函数,但在具体的选取 最佳搜索节点时的策略不同。象局部择优搜索法,就是在搜索的过程 中 选取“最
5、佳节点”后舍弃其他的兄弟节点,父亲节点,而一直得搜 索下去。这种搜索的结果很明显,由于舍 弃了其他的节点,可能也把 最好的节点都舍弃了,因为求解的最佳节点只是在该阶段的最佳并不 一定是全局 的最佳。最好优先就聪明多了,他在搜索时,便没有舍弃 节点(除非该节点是死节点),在每一步的估价中 都把当前的节点和 以前的节点的估价值比较得到一个“最佳的节点”。这样可以有效的 防止“最佳节点”的 丢失。那么A*算法又是一种什么样的算法呢? 其实A*算法也是一种最好优先的算法。只不过要加上一些约束 条件 罢了。由于在一些问题求解时,我们希望能够求解出状态空间搜索的 最短路径,也就是用最快的方法求 解问题,A
6、*就是干这种事情的! 我们先下个定义,如果一个估价函数可以找出最短的路径,我们称之 为可采 纳性。A*算法是一个可采纳的最好优先算法。A*算法的估价 函数可表示为: f(n) = g(n) + h(n) 这里,f(n)是估价函数,g(n)是起点到终点的最短路径值,h(n)是 n到目标的最断路经的启发值。由 于这个f(n)其实是无法预先知道的 ,所以我们用前面的估价函数f(n)做近似。g(n)代替g(n),但 g(n)=g(n) 才可(大多数情况下都是满足的,可以不用考虑), h(n)代替h(n),但h(n)g = 0; /这是计算h值 Node-h = (dx-sx)*(dx-sx) + (d
7、y-sy)*(dy-sy); /此处按道理应用开方 /这是计算f值,即估价值 Node-f = Node-g+Node-h; Node-NodeNum = TileNum(dx, dy); Node-x = dx; Node-y = dy; OPEN-NextNode=Node; / make Open List point to first node for (;) /从Open表中取得一个估价值最好的节点 BestNode=ReturnBestNode(); /如果该节点是目标节点就退出 if (BestNode-NodeNum = TileNumDest) / if weve found
8、 the /end, break and finish break; /否则生成子节点 GenerateSuccessors(BestNode,sx,sy); PATH = BestNode; 再看看生成子节点函数 GenerateSuccessors: void AstarPathfinder:GenerateSuccessors(NODE *BestNode,int dx,int dy) int x, y; /哦!依次生成八个方向的子节点,简单! / Upper-Left if ( FreeTile(x=BestNode-x-TILESIZE, y=BestNode-y-TILESIZE)
9、 ) GenerateSucc(BestNode,x,y,dx,dy); / Upper if ( FreeTile(x=BestNode-x, y=BestNode-y-TILESIZE) ) GenerateSucc(BestNode,x,y,dx,dy); / Upper-Right if ( FreeTile(x=BestNode-x+TILESIZE, y=BestNode-y-TILESIZE) ) GenerateSucc(BestNode,x,y,dx,dy); / Right if ( FreeTile(x=BestNode-x+TILESIZE, y=BestNode-y)
10、 ) GenerateSucc(BestNode,x,y,dx,dy); / Lower-Right if ( FreeTile(x=BestNode-x+TILESIZE, y=BestNode-y+TILESIZE) ) GenerateSucc(BestNode,x,y,dx,dy); / Lower if ( FreeTile(x=BestNode-x, y=BestNode-y+TILESIZE) ) GenerateSucc(BestNode,x,y,dx,dy); / Lower-Left if ( FreeTile(x=BestNode-x-TILESIZE, y=BestNo
11、de-y+TILESIZE) ) GenerateSucc(BestNode,x,y,dx,dy); / Left if ( FreeTile(x=BestNode-x-TILESIZE, y=BestNode-y) ) GenerateSucc(BestNode,x,y,dx,dy); 看看最重要的函数GenerateSucc: void AstarPathfinder:GenerateSucc(NODE *BestNode,int x,int y,int dx,int dy) int g, TileNumS, c = 0; NODE *Old, *Successor; /计算子节点的 g
12、值 g = BestNode-g+1; /g(Successor)=g(BestNode)+cost of getting /from BestNode to Successor TileNumS = TileNum(x,y); / identification purposes /子节点再Open表中吗? if ( (Old=CheckOPEN(TileNumS) != NULL ) / if equal to NULL then /not in OPEN list, else it returns the Node in Old /若在 for( c = 0; c Childc = NUL
13、L ) / Add Old to the list of / BestNodes Children (or Successors). break; BestNode-Childc = Old; /比较Open表中的估价值和当前的估价值(只要比较g值就可以了) if ( g g ) / if our new g value is Parent = BestNode; Old-g = g; Old-f = g + Old-h; else /在Closed表中吗? if ( (Old=CheckCLOSED(TileNumS) != NULL ) / if equal to NULL then /
14、not in OPEN list, else it returns the Node in Old /若在 for( c = 0; cChildc = NULL ) / Add Old to the list of /BestNodes Children (or Successors). break; BestNode-Childc = Old; /比较Closed表中的估价值和当前的估价值(只要比较g值就可以了) if ( g g ) / if our new g value is Parent = BestNode; Old-g = g; Old-f = g + Old-h; /再依次更新
15、Old的所有子节点的估价值 PropagateDown(Old); / Since we changed the g value of /Old,we need to propagate this new /value downwards, i.e. / do a Depth-First traversal of the tree! else/不在Open表中也不在Close表中 /生成新的节点 Successor = ( NODE* )calloc(1,sizeof( NODE ); Successor-Parent = BestNode; Successor-g = g; Successo
16、r-h = (x-dx)*(x-dx) + (y-dy)*(y-dy); / should do / sqrt(), but since we dont really Successor-f = g+Successor-h; / care about the distance but /just which branch looks Successor-x = x; / better this should suffice. / Anyayz its faster. Successor-y = y; Successor-NodeNum = TileNumS; /再插入Open表中,同时排序。
17、Insert(Successor); / Insert Successor on OPEN list wrt f for( c =0; c Childc = NULL ) / Add Old to the / list of BestNodes Children (or Successors). break; BestNode-Childc = Successor; A*算法例题与习题例1: 8数码难题 :2 8 3 1 2 3 1 6 4 - 8 4(用最少的步数) 7 5 7 6 5用A*算法程序如下:program num8;type a33=array1.3,1.3 of 0.8; a
18、4=array1.4 of -1.1; node=record ch:a33; si,sj:1.3; f:byte; pnt,dep,next:byte; end; const goal:a33=(1,2,3),(8,0,4),(7,6,5); start:a33=(2,8,3),(1,6,4),(7,0,5); di:a4=(0,-1,0,1); dj:a4=(-1,0,1,0); var data:array0.100 of node; temp:node; r,k,ni,nj,head,tail,depth:integer; function check(k:integer):boole
19、an; begin ni:=temp.si+dik;nj:=temp.sj+djk; if (ni in 1.3) and (nj in 1.3) then check:=true else check:=false; end; function dupe:boolean; var i,j,k:integer; buf:boolean; begin buf:=false;i:=0; repeat inc(i);buf:=true; for j:=1 to 3 do for k:=1 to 3 do if datai.chj,kdatatail.chj,k then buf:=false; until buf or (i=tail-1); dupe:=buf; end; function goals:boolean; var i,j:byte; begin goals:=true; for i:=1 to 3 do
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1