A星算法详解Word文档格式.docx

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

A星算法详解Word文档格式.docx

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

A星算法详解Word文档格式.docx

>

g(n)时,可以省略g(n),而提高效率。

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

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

二、初识A*算法

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

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

当然A*也是。

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

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

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

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

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

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

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

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

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

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

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)<

=h'

(n)才可(这一点特别的重要)。

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

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

哈!

你懂了吗?

肯定没懂!

接着看!

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

其中g(n)是节点所在的层数,h(n)=0,这种h(n)肯定小于h'

(n),所以由前述可知广度优先算法是一种可采纳的。

实际也是。

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

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

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

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

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

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

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

可难了,这就看你的了!

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

哈哈!

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

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

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

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

 Sunway?

?

深入A*算法

一、前言

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

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

  这里所举的例子是参考AMIT主页中的一个,使用这个源程序时,应该遵守一定的公约。

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

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

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

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

  如图有如下的状态空间:

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

  搜索过程中设置两个表:

OPEN和CLOSED。

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

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

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

具体搜索过程如下:

1)初始状态:

                

 OPEN=[A5];

CLOSED=[];

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

 OPEN=[B4,C4,D6];

CLOSED=[A5]

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

 OPEN=[C4,E5,F5,D6];

CLOSED=[B4,A5]

4)估算C4;

取得搜有子节点,并放入OPEN表中;

 OPEN=[H3,G4,E5,F5,D6];

CLOSED=[C4,B4,A5]

5)估算H3,取得搜有子节点,并放入OPEN表中;

 OPEN=[O2,P3,G4,E5,F5,D6];

CLOSED=[H3,C4,B4,A5]

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

 OPEN=[P3,G4,E5,F5,D6];

CLOSED=[O2,H3,C4,B4,A5]

7)估算P3,已得到解;

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

算法的伪程序如下:

Best_First_Search()

{

 Open=[起始节点];

 Closed=[];

 while(Open表非空)

 {

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

  if(X是目标节点)

  {

   求得路径PATH;

   返回路径PATH;

  }

  for(每一个X的子节点Y)

   if(Y不在OPEN表和CLOSE表中)

   {

    求Y的估价值;

    并将Y插入OPEN表中;

   }

   //还没有排序

   elseif(Y在OPEN表中)

    if(Y的估价值小于OPEN表的估价值)

     更新OPEN表中的估价值;

   else//Y在CLOSE表中

    if(Y的估价值小于CLOSE表的估价值)

    {

     更新CLOSE表中的估价值;

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

    }

   将X节点插入CLOSE表中;

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

  }//endfor

 }//endwhile

}//endfunc

  啊!

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

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

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

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

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

不清楚可以找我。

我的Email在文章尾。

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

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

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

^_*

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

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

里面带了一个EXE文件。

可以先看看。

  先复习一下,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因为有八个方向。

如图:

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

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

开始讲解源程序了。

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

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

  先看搜索主函数:

voidAstarPathfinder:

:

FindPath(intsx,intsy,intdx,intdy)

NODE*Node,*BestNode;

intTileNumDest;

//得到目标位置,作判断用

TileNumDest=TileNum(sx,sy);

//生成Open和Closed表

OPEN=(NODE*)calloc(1,sizeof(NODE));

CLOSED=(NODE*)calloc(1,sizeof(NODE));

//生成起始节点,并放入Open表中

Node=(NODE*)calloc(1,sizeof(NODE));

Node->

g=0;

//这是计算h值

//shouldreallyusesqrt().

h=(dx-sx)*(dx-sx)+(dy-sy)*(dy-sy);

//这是计算f值,即估价值

f=Node->

g+Node->

h;

NodeNum=TileNum(dx,dy);

x=dx;

y=dy;

//makeOpenListpointtofirstnode

OPEN->

NextNode=Node;

for(;

;

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

BestNode=ReturnBestNode();

//如果该节点是目标节点就退出

//ifwe'

vefoundtheend,breakandfinishbreak;

if(BestNode->

NodeNum==TileNumDest)

//否则生成子节点

GenerateSuccessors(BestNode,sx,sy);

}

PATH=BestNode;

  再看看生成子节点函数:

GenerateSuccessors(NODE*BestNode,intdx,int dy)

intx,y;

//哦!

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

//Upper-Left

if(FreeTile(x=BestNode->

x-TILESIZE,y=BestNode->

y-TILESIZE))

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

//Upper

x,y=BestNode->

//Upper-Right

x+TILESIZE,y=BestNode->

//Right

y))

//Lower-Right

y+TILESIZE))

//Lower

//Lower-Left

//Left

  看看最重要的函数:

GenerateSucc(NODE*BestNode,intx,inty,intdx,intdy)

intg,TileNumS,c=0;

NODE*Old,*Successor;

//计算子节点的g值

//g(Successor)=g(BestNode)+costofgettingfromBestNodetoSuccessor

g=BestNode->

g+1;

//identificationpurposes

TileNumS=TileNum(x,y);

//子节点再Open表中吗?

//ifequaltoNULLthennotinOPENlist,elseitreturnstheNodeinOld

if((Old=CheckOPEN(TileNumS))!

=NULL)

//若在

for(c=0;

c<

8;

c++)

//AddOldtothelistofBestNode'

sChildren(orSuccessors).

Child[c]==NULL)

break;

BestNode->

Child[c]=Old;

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

//ifournewgvalueis<

Old'

sthenresetOld'

sparenttopointtoBestNode

if(g<

Old->

g)

//当前的估价值小就更新Open表中的估价值

Parent=BestNode;

g=g;

f=g+Old->

else

//在Closed表中吗?

if((Old=CheckCLOSED(TileNumS))!

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

//当前的估价值小就更新Closed表中的估价值

//再依次更新Old的所有子节点的估价值

//SincewechangedthegvalueofOld,weneed

//topropagatethisnewvaluedownwards,i.e.

//doaDepth-Firsttraversalofthetree!

PropagateDown(Old);

//不在Open表中也不在Close表中

//生成新的节点

Successor=(NODE*)calloc(1,sizeof(NODE));

Successor->

//shoulddosqrt(),butsincewedon'

treally

h=(x-dx)*(x-dx)+(y-dy)*(y-dy);

//careaboutthedistancebutjustwhichbranchlooks

f=g+Successor->

//betterthisshouldsuffice.Anyayzit'

sfaster.

x=x;

y=y;

NodeNum=TileNumS;

//再插入Open表中,同时排序。

//InsertSuccessoronOPENlistwrtf

Insert(Successor);

Child[c]=Successor;

  哈哈!

A*算法我懂了!

当然,我希望你有这样的感觉!

不过我还要再说几句。

仔细看看这个程序,你会发现,这个程序和我前面说的伪程序有一些不同,在GenerateSucc函数中,当子节点在Closed表中时,没有将子节点从Closed表中删除并放入Open表中。

而是直接的重新的计算该节点的所有子节点的估价值(用PropagateDown函数)。

这样可以快一些!

另当子节点在Open表和Closed表中时,重新的计算估价值后,没有重新的对Open表中的节点排序,我有些想不通,为什么不排呢?

-(,会不会是一个小小的BUG。

你知道告诉我好吗?

  好了!

主要的内容都讲完了,还是完整仔细的看看源程序吧!

希望我所的对你有一点帮助,一点点也可以。

如果你对文章中的观点有异议或有更好的解释都告诉我。

我的email在文章最后!

 

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

当前位置:首页 > 求职职场 > 简历

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

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