A星详解.docx

上传人:b****5 文档编号:7911396 上传时间:2023-01-27 格式:DOCX 页数:8 大小:24.54KB
下载 相关 举报
A星详解.docx_第1页
第1页 / 共8页
A星详解.docx_第2页
第2页 / 共8页
A星详解.docx_第3页
第3页 / 共8页
A星详解.docx_第4页
第4页 / 共8页
A星详解.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

A星详解.docx

《A星详解.docx》由会员分享,可在线阅读,更多相关《A星详解.docx(8页珍藏版)》请在冰豆网上搜索。

A星详解.docx

A星详解

    A算法详解GC__P_{Z]u 

)]c]el__@y 

(c(-E_|u._ 

|

Tr1[ 

第一部分:

A*算法简介IFd_)OZ5 

  写这篇文章的初衷是应一个网友的要求,当然我也发现现在有关人工智能的中文站点实在太少,我在这里抛砖引玉,希望大家都来热心的参与。

 4T__-,'P{?

 

  还是说正题,我先拿A*算法开刀,是因为A*在游戏中有它很典型的用法,是人工智能在游戏中的代表。

 p4m__^_~e 

  A*算法在人工智能中是一种典型的启发式搜索算法,为了说清楚A*算法,我看还是先说说何谓启发式算法。

 _Sk6b`W_7$ 

=~GE?

}.o_ 

一、何谓启发式搜索算法:

 _/v}_P)& 

5cy_ddlaat 

  在说它之前先提提状态空间搜索。

状态空间搜索,如果按专业点的说法就是将问题求解过程表现为从初始状态到目标状态寻找这个路径的过程。

通俗点说,就是在解一个问题时,找到一条解题的过程可以从求解的开始到问题的结果(好象并不通俗哦)。

由于求解问题的过程中分枝有很多,主要是求解过程中求解条件的不确定性,不完备性造成的,使得求解的路径很多这就构成了一个图,我们说这个图就是状态空间。

问题的求解实际上就是在这个图中找到一条路径可以从开始到结果。

这个寻找的过程就是状态空间搜索。

 Lv`#zgo_f 

Zd_v_.

PGn 

  常用的状态空间搜索有深度优先和广度优先。

广度优先是从初始状态一层一层向下找,直到找到目标为止。

深度优先是按照一定的顺序前查找完一个分支,再查找另一个分支,以至找到目标为止。

这两种算法在数据结构书中都有描述,可以参看这些书得到更详细的解释。

 UJee_&4C-y 

Z

i2_o__ 

  前面说的广度和深度优先搜索有一个很大的缺陷就是他们都是在一个给定的状态空间中穷举。

这在状态空间不大的情况下是很合适的算法,可是当状态空间十分大,且不预测的情况下就不可取了。

他的效率实在太低,甚至不可完成。

在这里就要用到启发式搜索了。

 Q0pC4_W_J` 

0lX)

_C__l 

  启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。

这样可以省略大量无畏的搜索路径,提到了效率。

在启发式搜索中,对位置的估价是十分重要的。

采用了不同的估价可以有不同的效果。

我们先看看估价是如何表示的。

 1_L+=|*:

 

O0@___w(L- 

  启发中的估价是用估价函数表示的,如:

 8_|1`_Tn}o 

W3^_zIj 

  f(n)=g(n)+h(n) w-UKMW9" 

6ex_RS]BI 

  其中f(n)是节点n的估价函数,g(n)实在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。

在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。

如果说详细点,g(n)代表了搜索的广度的优先趋势。

但是当h(n)>>g(n)时,可以省略g(n),而提高效率。

这些就深了,不懂也不影响啦!

我们继续看看何谓A*算法。

 %4j&H!

y-w; 

Uh>.v|P6 

二、初识A*算法:

 __N_A+_&jV 

CV___s8s 

  启发式搜索其实有很多的算法,比如:

局部择优搜索法、最好优先搜索法等等。

当然A*也是。

这些算法都使用了启发函数,但在具体的选取最佳搜索节点时的策略不同。

象局部择优搜索法,就是在搜索的过程中选取“最佳节点”后舍弃其他的兄弟节点,父亲节点,而一直得搜索下去。

这种搜索的结果很明显,由于舍弃了其他的节点,可能也把最好的节点都舍弃了,因为求解的最佳节点只是在该阶段的最佳并不一定是全局的最佳。

最好优先就聪明多了,他在搜索时,便没有舍弃节点(除非该节点是死节点),在每一步的估价中都把当前的节点和以前的节点的估价值比较得到一个“最佳的节点”。

这样可以有效的防止“最佳节点”的丢失。

那么A*算法又是一种什么样的算法呢?

其实A*算法也是一种最好优先的算法。

只不过要加上一些约束条件罢了。

由于在一些问题求解时,我们希望能够求解出状态空间搜索的最短路径,也就是用最快的方法求解问题,A*就是干这种事情的!

我们先下个定义,如果一个估价函数可以找出最短的路径,我们称之为可采纳性。

A*算法是一个可采纳的最好优先算法。

A*算法的估价函数克表示为:

 pJd0k"_{_ 

|Dg;__(i?

  f’(n)=g’(n)+h’(n) (YIhTSL"] 

xY|yI> 

  这里,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)<=h’(n)才可(这一点特别的重要)。

可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。

我们说应用这种估价函数的最好优先算法就是A*算法。

哈!

你懂了吗?

肯定没懂!

接着看!

[#___0Yt/G 

E&Bn8L~_O 

  举一个例子,其实广度优先算法就是A*算法的特例。

其中g(n)是节点所在的层数,h(n)=0,这种h(n)肯定小于h’(n),所以由前述可知广度优先算法是一种可采纳的。

实际也是。

当然它是一种最臭的A*算法。

 _WE_")xhV6 

_W}>=JoN^J 

  再说一个问题,就是有关h(n)启发函数的信息性。

h(n)的信息性通俗点说其实就是在估计一个节点的值时的约束条件,如果信息越多或约束条件越多则排除的节点就越多,估价函数越好或说这个算法越好。

这就是为什么广度优先算法的那么臭的原因了,谁叫它的h(n)=0,一点启发信息都没有。

但在游戏开发中由于实时性的问题,h(n)的信息越多,它的计算量就越大,耗费的时间就越多。

就应该适当的减小h(n)的信息,即减小约束条件。

但算法的准确性就差了,这里就有一个平衡的问题。

可难了,这就看你的了!

 _^\:

_yf.k 

Uh.Sc:

trA 

  好了我的话也说得差不多了,我想你肯定是一头的雾水了,其实这是写给懂A*算法的同志看的。

哈哈!

你还是找一本人工智能的书仔细看看吧!

我这几百字是不足以将A*算法讲清楚的。

只是起到抛砖引玉的作用希望大家热情参与吗!

 @44_P_4_?

h4__Ia>^@_ 

  预知A*算法的应用,请看《深入A*算法》。

Z__v4_

|q__!

._a 

第二部分:

深入A*算法———浅析A*算法在搜索最短路径中的应用#XI"@_pD__ 

a_zo0{`S?

一、前言 :

mpiAs<%U" 

GAQ'Ti1!

 

  在这里我将对A*算法的实际应用进行一定的探讨,并且举一个有关A*算法在最短路径搜索的例子。

值得注意的是这里并不对A*的基本的概念作介绍,如果你还对A*算法不清楚的话,请看姊妹篇《初识A*算法》。

 1TjZ#yP%1 

yG&2U_q_X 

  这里所举的例子是参考AMIT主页中的一个源程序,你可以在AMIT的站点上下载也可以在我的站点上下载。

你使用这个源程序时,应该遵守一定的公约。

 _5_lTD]d_ 

B,_

`btJ_h 

二、A*算法的程序编写原理 KFDS_q_"j 

(R'+_j_WH 

  我在《初识A*算法》中说过,A*算法是最好优先算法的一种。

只是有一些约束条件而已。

我们先来看看最好优先算法是如何编写的吧。

 rGlRAn#?

_zoP_%u,XL 

  如图有如下的状态空间:

(起始位置是A,目标位置是P,字母后的数字表示节点的估价值) 

F___tv8@l 

@(:

___v__l 

  搜索过程中设置两个表:

OPEN和CLOSED。

OPEN表保存了所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。

算法中有一步是根据估价函数重排OPEN表。

这样循环中的每一步只考虑OPEN表中状态最好的节点。

具体搜索过程如下:

 t`G)

b&3_O 

9vI]L_fP 

  1)初始状态:

S#8>Zw_Q 

  OPEN=[A5];CLOSED=[];,_P6=~q3k 

  2)估算A5,取得搜有子节点,并放入OPEN表中;5P_ZN^\^__ 

  OPEN=[B4,C4,D6];CLOSED=[A5]0JYWrP_R 

  3)估算B4,取得搜有子节点,并放入OPEN表中;_"X__n%at4 

  OPEN=[C4,E5,F5,D6];CLOSED=[B4,A5]I,O#X)O|i_ 

  4)估算C4;取得搜有子节点,并放入OPEN表中;2~c~{jl_\ 

  OPEN=[H3,G4,E5,F5,D6];CLOSED=[C4,B4,A5]___>UHa 

  5)估算H3,取得搜有子节点,并放入OPEN表中;I*\_^_,ow_ 

  OPEN=[O2,P3,G4,E5,F5,D6];CLOSED=H3C4,B4,A5]|(_%u}V?

  6)估算O2,取得搜有子节点,并放入OPEN表中;SK_XD^O_H 

  OPEN=[P3,G4,E5,F5,D6];CLOSED=[O2,H3,C4,B4,A5]ijUzC>O_+q 

  7)估算P3,已得到解;Llz[_'"_m 

  看了具体的过程,再看看伪程序吧。

算法的伪程序如下:

 _ii4B?

__E_ 

rZwB>__c 

Best_First_Search()_p!

W[X%`

) 

{:

q+N&

j'3_ 

Open=[起始节点];Closed=[];RK_Tb'3H 

while(Open表非空)+,flE=5]s 

{G?

hK9@|_v 

从Open中取得一个节点X,并从OPEN表中删除。

"="O_>__ 

if(X是目标节点)/_"#4T^7& 

{;b%_{ilx:

求得路径PATH;返回路径PATH;uJow7-FD_ 

}H__;KDZO9W 

for(每一个X的子节点Y)Hi,t@_!

_!

 

{%|"Qi]c_d 

if(Y不在OPEN表和CLOSE表中)_w_2"_]Pl 

{>bm|%_O_u" 

求Y的估价值;并将Y插入OPEN表中;//还没有排序_}NmNanW^ 

}&a)vdlZSE= 

else'_Z8aPH_D 

if(Y在OPEN表中)J)

x3\[}Ye 

{3C^1f_rF_ 

if(Y的估价值小于OPEN表的估价值)mP}#Cc_ji?

 

更新OPEN表中的估价值;_lpC_@I^:

 

}

_B@K__[3 

else//Y在CLOSE表中y_p]@_^TN 

{"^r__Nr_ 

if(Y的估价值小于CLOSE表的估价值)_LI_W*4r!

 

{C_lU_Sr_Sp 

更新CLOSE表中的估价值;=n_R__uY' 

从CLOSE表中移出节点,并放入OPEN表中;_._5Z_EO 

}b:

MG@H_xc_ 

}3N4.$#>#9@ 

将X节点插入CLOSE表中;9_6Z_dM= 

按照估价值将OPEN表中的节点排序;!

_]b@RU__U 

}//endfork

BsXfVs_9 

}//endwhile!

:

us!

s___ 

}//endfunc])_T/_sO#' 

b|?

;h2_1rG 

  啊!

伪程序出来了,写一个源程序应该不是问题了,依葫芦画瓢就可以。

A*算法的程序与此是一样的,只要注意估价函数中的g(n)的h(n)约束条件就可以了。

不清楚的可以看看《初识A*算法》。

好了,我们可以进入另一个重要的话题,用A*算法实现最短路径的搜索。

在此之前你最好认真的理解前面的算法。

不清楚可以找我。

我的Email在文章尾。

 HeIS;g_fUY 

_|_B[__eJq 

三、用A*算法实现最短路径的搜索 _JP_=Z_U_u 

bkv/I{C>_?

 

  在游戏设计中,经常要涉及到最短路径的搜索,现在一个比较好的方法就是用A*算法进行设计。

他的好处我们就不用管了,反正就是好!

^_* bZ5n_,KQA5 

^.HWk_S`e 

%z)EO9vt_r 

  注意下面所说的都是以ClassAstar这个程序为蓝本,你可以在这里下载这个程序。

这个程序是一个完整的工程。

里面带了一个EXE文件。

可以先看看。

 p_\D_>z(" 

)f*Iomp]@ 

  先复习一下,A*算法的核心是估价函数f(n),它包括g(n)和h(n)两部分。

g(n)是已经走过的代价,h(n)是n到目标的估计代价。

在这个例子中g(n)表示在状态空间从起始节点到n节点的深度,h(n)表示n节点所在地图的位置到目标位置的直线距离。

啊!

一个是状态空间,一个是实际的地图,不要搞错了。

再详细点说,有一个物体A,在地图上的坐标是(xa,ya),A所要到达的目标b的坐标是(xb,yb)。

则开始搜索时,设置一个起始节点1,生成八个子节点2-9因为有八个方向。

如图:

 _0__dt"ZSm 

A*0_*s__Z0 

  仔细看看节点1、9、17的g(n)和h(n)是怎么计算的。

现在应该知道了下面程序中的f(n)是如何计算的吧。

开始讲解源程序了。

其实这个程序是一个很典型的教科书似的程序,也就是说只要你看懂了上面的伪程序,这个程序是十分容易理解的。

不过他和上面的伪程序有一些的不同,我在后面会提出来。

 B,y3]g6u 

w_n84?

$BGd 

先看搜索主函数:

 _rjBc_;a 

+x_]e-P% 

voidAstarPathfinder:

:

FindPath(intsx,intsy,intdx,intdy)^!

u_O(B& 

{RV92qnB_ 

NODE*Node,*BestNode;P"Rk_?

_lL 

intTileNumDest;_R____Kk" 

//得到目标位置,作判断用+_Ag#B_*_ 

TileNumDest=TileNum(sx,sy);{6tx,;r(F 

//生成Open和Closed表_T_&*_eOr 

OPEN=(NODE*)calloc(1,sizeof(NODE));g&>mP?

 

CLOSED=(NODE*)calloc(1,sizeof(NODE));W_D%|Ub2X 

//生成起始节点,并放入Open表中my=_~"bw_4 

Node=(NODE*)calloc(1,sizeof(NODE));_LOt#1_Qv 

Node->g=0;9Burj_G1k?

 

//这是计算h值oHRbAE^_ 

Node->h=(dx-sx)*(dx-sx)+(dy-sy)*(dy-sy);//shouldreallyusesqrt().+}Auk|>_Dc 

//这是计算f值,即估价值5Wl,J_

Node->f=Node->g+Node->h;C}bPv+_t 

Node->NodeNum=TileNum(dx,dy);i&5!

9m`_Cw 

Node->x=dx;

_.Btv}__b 

Node->y=dy;ur`}_v_|ZY 

OPEN->NextNode=Node;//makeOpenListpointtofirstnode5u_"nxT_ 

for(;;)_W*|O_Oa' 

{//从Open表中取得一个估价值最好的节点0n7_Hk_Do_ 

BestNode=ReturnBestNode();j_Cam,$o_E 

//如果该节点是目标节点就退出_}.w#__X_ 

if(BestNode->NodeNum==TileNumDest)//ifwe’vefoundtheend,breakandfinishWJBW:

2=; 

break;_!

~____Ax_ 

//否则生成子节点%_y!

____ 

GenerateSuccessors(BestNode,sx,sy);{8l_d:

ZP_ 

}z[__R"+_ 

PATH=BestNode;

%k_aTQ"PB 

}=k_yJaT^5[ 

再看看生成子节点函数GenerateSuccessors:

 m3h2/}_%9` 

voidAstarPathfinder:

:

GenerateSuccessors(NODE*BestNode,intdx,intdy)_Y*h`_),_ 

{p

I__M*c6 

intx,y;1_gf/#+$\ 

//哦!

依次生成八个方向的子节点,简单!

o_X_

%PsS 

//Upper-Leftox_xE'cx{g 

if(FreeTile(x=BestNode->x-TILESIZE,y=BestNode->y-TILESIZE))6i*p+S?

U" 

GenerateSucc(BestNode,x,y,dx,dy);N9fUlXhR_ 

//UpperY_2ah__zB 

if(FreeTile(x=BestNode->x,y=BestNode->y-TILESIZE))!

>_"_I_Nmz 

GenerateSucc(BestNode,x,y,dx,dy);b[_Q_C

M/_ 

//Upper-Right6c;_?

`

__C 

if(FreeTile(x=BestNode->x+TILESIZE,y=BestNode->y-TILESIZE))z[<_p_i_:

 

GenerateSucc(BestNode,x,y,dx,dy);c@_"___i_?

 

//Right10QNV=yK7s 

if(FreeTile(x=BestNode->x+TILESIZE,y=BestNode->y))_B7x"ef_ 

GenerateSucc(BestNode,x,y,dx,dy);_"pKGUM__

 

//Lower-Right_~-o^eI_4_ 

if(FreeTile(x=BestNode->x+TILESIZE,y=BestNode->y+TILESIZE))qjda_hV_Y_ 

GenerateSucc(BestNode,x,y,dx,dy);S^sW._(_I 

//Lower__]pucv!

if(FreeTile(x=BestNode->x,y=BestNode->y+TILESIZE))Qn_u&GB__M 

GenerateSucc(BestNode,x,y,dx,dy);[fJFH^&?

hr 

//Lower-Leftd$G%F$BTs 

if(FreeTile(x=BestNode->x-TILESIZE,y=BestNode->y+TILESIZE))/:

__c_,v- 

GenerateSucc(BestNode,x,y,dx,dy);FrQ-_v]_c 

//Left@bVh?

T0~F, 

if(FreeTile(x=BestNode->x-TILESIZE,y=BestNode->y))JOoLH_ZQ1v 

GenerateSucc(BestNode,x,y,dx,dy);_T_VE_F+t 

}(>@syF%PB_ 

:

_[_cT,_3_ 

看看最重要的函数GenerateSucc:

 uq1(yyWp(_ 

voidAstarPathfinder:

:

GenerateSucc(NODE*BestNode,intx,inty,intdx,intdy)m_{=~|_I_ 

{g_T_\y&_ 

intg,TileNumS,c=0;w<^2h}__5 

NODE*Old,*Successor;o_\V_4qekk 

//计算子节点的g值6W#F__Ss~ 

g=BestNode->g+1;//g(Successor)=g(BestNode)+costofgettingfromBestNodetoSuccessorp]IhQnj2__ 

TileNumS=TileNum(x,y);//identificationpurposes1*`Jc_Un,> 

//子节点再Open表中吗?

LRlk9:

QD> 

if((Old=CheckOPEN(TileNumS))!

=NULL)//ifequaltoNULLthennotinOPENlist,elseitreturnstheNodeinOld___._

{|k9j)H_g( 

//若在hI#M{cz__ 

for(c=0;c<8;c++)if(BestNode->Child[c]==NULL)//AddOldtothelistofBestNode’sChildren(orSuccessors).__T_KutO0 

break;4F__c1_' 

BestNode->Child[c]=Old;uN^qfJ'@> 

//比较Open表中的估价值和当前的估价值(只要比较g值就可以了)r__V_W'_KN 

if(gg)//ifournewgvalueisParent=BestNode;s17gi_,"X 

Old->g=g;xB_]_v_ 

Old->f=g+Old->h;~G^do

j3|+ 

}__'cc4Y~0s 

}_BA_lkN+_D 

else//在Closed表中吗?

f9bz:

_;W__ 

if((Old=CheckCLOSED(TileNumS))!

=NULL)//ifequaltoNULLthennotinOPENlist,elseitreturnstheNodeinOld_Qn_Af_A% 

{g_Q_t_@xNO 

//若在8WQ%rN_={8 

for(c=0;c<8;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 文学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1