人工智能作业.docx
- 文档编号:9995670
- 上传时间:2023-02-07
- 格式:DOCX
- 页数:19
- 大小:78.12KB
人工智能作业.docx
《人工智能作业.docx》由会员分享,可在线阅读,更多相关《人工智能作业.docx(19页珍藏版)》请在冰豆网上搜索。
人工智能作业
人工智能课程设计
用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; }; stack stack 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) {//回溯路径并输出 stack while(! a->parent==NULL) { Path.push(a); a=a->parent; } Path.push(a); while(! Path.empty()) { cout<<"("< Path.pop(); } } Walked*Exist_OPEN(Walked*a) {//判断节点是否存在与open堆栈 stack 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堆栈 stack 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+1 { 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+1 { 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; stack intb=OPEN.size(); for(inti=0;i { p=OPEN.top(); OPEN.pop(); x=i+1; while(x { q=OPEN.top(); OPEN.pop(); if(q->f { 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<<"长度为: "< 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*算法解决迷宫的最短路径问题,使我充分认识到启发式搜索算法的优点。 在以后的编程搜索算法中,可以适当的运用这一十分有效率的算法,以达到提高程序效率的目的。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 人工智能 作业