人工智能作业.docx

上传人:b****8 文档编号:9995670 上传时间:2023-02-07 格式:DOCX 页数:19 大小:78.12KB
下载 相关 举报
人工智能作业.docx_第1页
第1页 / 共19页
人工智能作业.docx_第2页
第2页 / 共19页
人工智能作业.docx_第3页
第3页 / 共19页
人工智能作业.docx_第4页
第4页 / 共19页
人工智能作业.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

人工智能作业.docx

《人工智能作业.docx》由会员分享,可在线阅读,更多相关《人工智能作业.docx(19页珍藏版)》请在冰豆网上搜索。

人工智能作业.docx

人工智能作业

人工智能课程设计

 

 

用A*算法编写迷宫问题

 

学院:

班级:

姓名:

学号:

一、程序目的

通过编制迷宫程序来熟练掌握A*算法并熟悉和掌握A*算法实现迷宫寻路功能,要求掌握启发式函数的编写以及各类启发式函数效果的比较。

二、算法概述

下面给出A*算法:

OPEN:

=(s),f(s)=g(s)+h(s)=h(s),fm:

=0;

LOOP:

IFOPEN=()THENEXIT(FAIL);

NEST:

={ni|f(ni)

IFNEST!

=()THENn:

=NEST不空是,取其中g最小者作为当前节点,否则取OPEN的第一个当前节点。

IFGOAL(n)THENEXIT(SUCCESS);

REMOVE(n,OPEN),ADD(n,CLOSED);

EXPAND(n)→{mi},计算f(n,mi):

=g(n,mi)+h(mi);g(n,mi)是从s通过n到mi的耗散值,f(n,mi)是从s通过n、mi到目标结点耗散值的估计;

ADD(mi,OPEN),标记mi到n的指针。

IFf(n,mi)

=f(n,mk),标记mk到n的指针;比较f(n,mk)和f(mk),f(mk)是扩展n之前计算的耗散值。

IFf(n,m1)

OPEN中的节点按f值从小到达排序;

GOLOOP。

 

下面给出源程序中所定义的函数:

boolbound(Walked*a)

a为structWalked类型的节点

该函数确定了迷宫模型的边界

boolbound(Walked*a)

intFunction_h(Walked*a)

a为structWalked类型的节点

该函数求出节点的h(s)值并返回

voidWalking_Path(Walked*a)

a为structWalked类型的节点

该函数回溯a节点的父节点,并且输出从已确定的最短路径的从开始到目标节点的路径

Walked*Exist_OPEN(Walked*a)

a为structWalked类型的节点

该函数确定节点a是否存在于OPEN中,如果存在,则返回,如果不存在,return0

Walked*Exist_CLOSE(Walked*a)

a为structWalked类型的节点

该函数确定节点a是否存在于CLOSED中,如果存在,则返回,如果不存在,return0

voidExpand(Walked*a)

a为structWalked类型的节点

该函数为扩展函数,即扩展a节点,并按照A*算法的步骤

判断节点的可行性

voidSortStack()

该函数为排序函数,负责排序OPEN和CLOSED中的数据

intGoIntoMaze()

该函数负责初始化迷宫模型并且调用其他关键函数

voidPrintMaze()

该函数负责输出迷宫的模型

三、实验原理

(1)A*算法

A*(A-Star)算法是一种静态路网中求解最短路最有 效的方法。

公式表示为:

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

保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取:

估价值h(n)<=n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。

但能得到最优解。

如果估价值>实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。

其实A*算法也是一种最好优先的算法只不过要加上一些约束条件罢了。

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

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

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

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

f'(n)=g'(n)+h'(n)这里,f'(n)是估价函数,g'(n)是起点到节点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)的信息,即减小约束条件。

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

(2)迷宫问题

迷宫图从入口到出口有若干条道路,求从入口到出口最短路径的走法。

如图1为一简单迷宫示意图及其平面坐标表示。

以平面坐标图来表示迷宫的道路时,问题的状态以所处的坐标位置来表示,即综合数据库定义为(x,y),1<=x,

Y<=N(N为迷宫问题的最大坐标数),则迷宫问题归结为求(1,1)到(4,4)的最短路径问题。

迷宫走法规定为向东、南、西、北前进一步,由此可见得到规则集简化形式如下。

R1:

if(x,y)then(x+1,y)

R2:

if(x,y)then(x,y-1)

R3:

if(x,y)then(x-1,y)

R4:

if(x,y)then(x,y+1)

对于这个简单例子,可给出状态空间如图2所示。

为求得最佳路径,可使用A*算法。

假定搜索一步去单位耗散,则可定义:

h(n)=|XG-xn|+|YG-yn|

其中(XG,YG)为目标点坐标,(x,y)为节点n的坐标。

由于该迷宫问题所有路径都是水平或者垂直的,没有斜路,因此,h(n)=|XG-xn|+|YG-yn|显然可以满足A*的条件,即h(n)<=h*(n)。

取g(n)=d(n),有f(n)=d(n)+h(n)。

再设当不同结点的f值相等时,以深度优先排序,则搜索图如图3所示。

最短路径为((1,1),(1.2),(1,3),(2,3),(2,4),(3,4),(3,3),(4,3),(4,4))。

在该搜索图中,目标节点的f时8,有几个节点的f也是8,那么这几个f为8的节点,也有被扩展的可能,就看他们在OPEN表中的具体排列次序了。

这里假定了f相等时,以深度优先排序。

图1迷宫问题及其表示

图2状态空间图

图3迷宫问题启发式搜索图

四、实验内容

熟悉掌握A*算法,并用此算法解决迷宫的最短路径问题

运用编程语言,写出A*算法的源程序,并利用源程序打印迷宫模型,并找出通过迷宫的最短路径,并且输出。

迷宫模型如图

五、源代码(包含注释)

#include

#include

#include

usingnamespacestd;

intMazeMap[7][7]={{1,2,1,2,1,0,1},

{0,3,0,3,2,3,2},

{1,2,1,2,1,2,1},

{2,3,2,3,0,3,2},

{1,2,1,2,1,2,1},

{2,3,0,3,2,3,0},

{1,2,1,2,1,2,1}};//确定迷宫模型,0为不连接,1为节点,2为连接,3为空

structWalked

{

intx;

inty;

intg;

intf;

structWalked*parent;

};

stackOPEN;

stackCLOSE;//建立open和closed堆栈

boolbound(Walked*a)

{//确定迷宫边界

if(a->x>=0&&a->x<=6&&a->y>=0&&a->y<=6)

return1;

else

return0;

}

intFunction_h(Walked*a)

{//求出节点的H值

returnabs((6-a->x)/2)+abs((6-a->y)/2);

}

voidWalking_Path(Walked*a)

{//回溯路径并输出

stackPath;

while(!

a->parent==NULL)

{

Path.push(a);

a=a->parent;

}

Path.push(a);

while(!

Path.empty())

{

cout<<"("<x/2+1<<","<y/2+1<<")"<

Path.pop();

}

}

Walked*Exist_OPEN(Walked*a)

{//判断节点是否存在与open堆栈

stackr;

Walked*p,*q;

while(!

OPEN.empty())

{

p=OPEN.top();

if(p->x==a->x&&p->y==a->y)

{//存在,返回该节点指针

while(!

r.empty())

{

q=r.top();

r.pop();

OPEN.push(q);

}

returnp;

}

OPEN.pop();

r.push(p);

}

while(!

r.empty())

{

q=r.top();

r.pop();

OPEN.push(q);

}

return0;//不存在

}

Walked*Exist_CLOSE(Walked*a)

{//判断节点是否存在与closed堆栈

stackr;

Walked*p,*q;

while(!

CLOSE.empty())

{

p=CLOSE.top();

if(p->x==a->x&&p->y==a->y)

{//存在,返回该节点指针

while(!

r.empty())

{

q=r.top();

r.pop();

CLOSE.push(q);

}

returnp;

}

CLOSE.pop();

r.push(p);

}

while(!

r.empty())

{

q=r.top();

r.pop();

CLOSE.push(q);

}

return0;//不存在

}

voidExpand(Walked*a)

{//扩展节点并且按照A*算法的原则判断扩展节点的可行性

intxx,yy;

structWalked*b;

structWalked*Direction[4];

for(inti=0;i<4;i++)

{

Direction[i]=(structWalked*)malloc(sizeof(Walked));

}

Direction[0]->x=a->x+2;//向右扩展

Direction[0]->y=a->y;

Direction[1]->x=a->x-2;//向左扩展

Direction[1]->y=a->y;

Direction[2]->x=a->x;

Direction[2]->y=a->y-2;//向下扩展

Direction[3]->x=a->x;

Direction[3]->y=a->y+2;//向上扩展

for(i=0;i<4;i++)

{

if(bound(Direction[i]))

{//按照A*算法原则判断扩展节点的可行性

xx=(Direction[i]->x+a->x)/2;

yy=(Direction[i]->y+a->y)/2;

if(MazeMap[xx][yy]==2)

{

if(Exist_OPEN(Direction[i])==0&&Exist_CLOSE(Direction[i])==0)

{

Direction[i]->g=a->g+1;

Direction[i]->f=Direction[i]->g+Function_h(Direction[i]);

Direction[i]->parent=a;

OPEN.push(Direction[i]);

}

elseif(Exist_OPEN(Direction[i]))

{

b=Exist_OPEN(Direction[i]);

if(a->g+1g)

{

b->g=a->g+1;

b->f=b->g+Function_h(Direction[i]);

Direction[i]->parent=a;

}

}

elseif(Exist_CLOSE(Direction[i]))

{

b=Exist_CLOSE(Direction[i]);

if(a->g+1g)

{

b->g=a->g+1;

b->f=b->g+Function_h(Direction[i]);

Direction[i]->parent=a;

OPEN.push(Direction[i]);

}

}

}

}

}

}

voidSortStack()

{//为open和closed堆栈排序

Walked*p,*q,*r;

intx=0;

stackc;

intb=OPEN.size();

for(inti=0;i

{

p=OPEN.top();

OPEN.pop();

x=i+1;

while(x

{

q=OPEN.top();

OPEN.pop();

if(q->ff)

{

r=p;

p=q;

q=r;

}

OPEN.push(q);

x++;

}

c.push(p);

}

while(!

c.empty())

{

q=c.top();

c.pop();

OPEN.push(q);

}

}

intGoIntoMaze()

{

Walkeds={0,0,0,0,NULL};//初始化迷宫

Walked*n=&s;

OPEN.push(n);

while(true)

{

if(OPEN.empty())

{//寻找路径失败

cout<<"无法走出迷宫!

!

"<

return0;

}

else

{

n=OPEN.top();

if(n->x==6&&n->y==6)

{//寻找路径成功

cout<<"路径已找到!

!

"<

cout<<"长度为:

"<f<

cout<<"路径为:

"<

Walking_Path(n);

return1;

}

else

{//寻找中。

OPEN.pop();

CLOSE.push(n);

Expand(n);

SortStack();

}

}

}

}

voidPrintMaze()

{//输出迷宫模型

inti,j;

cout<<"迷宫如图:

"<

for(i=0;i<7;i++)

{

if(i%2==0)

{

for(j=0;j<7;j++)

{

if(MazeMap[i][j]==1)

{

cout<<"#";

}

elseif(MazeMap[i][j]==2)

{

cout<<"-";

}

elseif(MazeMap[i][j]==0)

{

cout<<"";

}

}

cout<

}

else

{

for(j=0;j<7;j++)

{

if(MazeMap[i][j]==2)

{

cout<<"|";

}

else

cout<<"";

}

cout<

}

}

}

voidmain()

{//调用输出迷宫和寻找路径函数

PrintMaze();

GoIntoMaze();

}

 

六、实验结果

七、实验总结

通过本次作业,加深了对搜索策略的认识。

启发式的搜索方不是像穷举的搜索办法一样,列举出所有可行的节点从而进行一一比对,来找到程序所要的目标节点,而是通过算法过程中的启发信息进行有目的的搜索,这样的做法使得搜索变得更有目的性,减少搜索的盲目性,并且这种算法能及时的排除掉那些不可能得到目标节点的节点,使得搜索算法变得更有效率。

运用A*算法解决迷宫的最短路径问题,使我充分认识到启发式搜索算法的优点。

在以后的编程搜索算法中,可以适当的运用这一十分有效率的算法,以达到提高程序效率的目的。

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

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

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

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