人工智能大作业

您所在的位置:网站首页 a*迷宫 人工智能大作业

人工智能大作业

2023-09-01 04:32| 来源: 网络整理| 查看: 265

项目设计的目的

利用A*算法实现迷宫寻路功能,利用启发式函数的编写以及各类启发式函数效果的比较。

相关原理知识介绍

A*(A-Star)算法是一种静态路网中求解最短路最有效的方法。公式表示为:f(n)=g(n)+h(n),其中f(n)是节点n从初始点到目标点的估价函数,g(n)是在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取:估价值h(n)小于等于n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低,但能得到最优解。如果估价值大于实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。 启发式搜索:启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无畏的搜索路径,提到了效率。在启发式搜索中,对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。

估价函数:从当前节点移动到目标节点的预估费用;这个估计就是启发式的。在寻路问题和迷宫问题中,我们通常用曼哈顿(manhattan)估价函数(下文有介绍)预估费用。

A算法与BFS:可以这样说,BFS是A算法的一个特例。对于一个BFS算法,从当前节点扩展出来的每一个节点(如果没有被访问过的话)都要放进队列进行进一步扩展。也就是说BFS的估计函数h永远等于0,没有一点启发式的信息,可以认为BFS是“最烂的”A算法。(注解:不一定是0,读者只要认为是“相同的”就可以了) 选取最小估价:如果学过数据结构的话,应该可以知道,对于每次都要选取最小估价的节点,应该用到最小优先级队列(也叫最小二叉堆)。在C++的STL里有现成的数据结构priority_queue,可以直接使用。当然不要忘了重载自定义节点的比较操作符。 A算法的特点:A*算法在理论上是时间最优的,但是也有缺点:它的空间增长是指数级别的。

设计的求解问题的流程图的说明

A*算法寻路的求解步骤说明: 1.将起点方格(节点)加入openlist链表中,作为寻路开始的起点; 2.循环执行以下步骤,直到openlist链表为空结束或者终点(节点)加入到 openlist 中: (1)在openlist中找到F值最小的那个节点(如果有相等的情况,就选择最先找到的那个节点)作为[ 当前节点 ]; (2)在openlist中将第1步找到的那个F值最小的节点,从openlist中删除掉; (3)在closelist中将第1步找到的那个F值最小的节点,加入closelist中; (4)围绕第1步找到的那个F值最小的 [ 当前节点 ] ,找到与它相邻的 四个方向(上下左右) 上的节点,这里要判断邻居节点的有效性,看 邻居节点 是否满足以下条件: 邻居节点是否越界——节点的x或者y是否在可视范围内; 邻居节点是否为障碍方格(节点)——比如本程序中的 MAZE[i][j]=1 即为障碍,MAZE[i][j]=0 即为可用; 邻居节点是否已经在openlist链表中或者closelist链表中; 以上都满足就抛弃不要,否则这个邻居节点就要留下来,并进行初始化: 【1】指定[当前节点]为这个[邻居节点]的父节点; 【2】计算[邻居节点]的G值; 【3】计算[邻居节点] 的H值; 【4】计算[邻居节点]的F值; 初始化完毕,将[邻居节点]加入openlist中; 3.如果找到了可寻的路径,利用节点的parent属性,回溯打印输出路径即可。

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225package graph; import java.util.ArrayList; import java.util.List; //A*寻路算法简单实现————>四方向(上下左右) public class Maze_A_ManHaDun {         //简单的迷宫模拟——利用二维数组,其中 1 表示障碍,不可通过。     public static final int[][] MAZE= {     {0, 1, 0, 0, 0, 0, 0},//7     {0, 0, 1, 0, 0, 0, 0},     {1, 0, 0, 1, 0, 0, 0},     {0, 1, 0, 1, 1, 1, 1},     {0, 0, 0, 0, 0, 0, 0},     {0, 0, 0, 0, 0, 0, 0},     {0, 0, 0, 1, 1, 1, 0},     //7     };         //定义 方格节点——grid     static class Grid{         public int x;//结点         public int y;         public int f;//fn         public int g;//gn         public int h;//hn         public Grid parent;                         public Grid(int x,int y) {             this.x=x;             this.y=y;         }                 //实例化一个方格节点         public void initGrid(Grid parent, Grid end) {             //parent赋值             this.parent=parent;                         //计算g的大小             if(parent!=null) {                 this.g=parent.g+1;                 //this.g=0;             }             else             {                 this.g=1;             }                         //计算h的大小             this.h=Math.abs(this.x-end.x)+Math.abs(this.y-end.y);             //this.h=Math.abs(this.x-end.x)*Math.abs(this.y-end.y);                 //计算f的大小             this.f=this.g+this.h;         }     }         //寻路算法核心实现过程     public static Grid aStarSearch(Grid start, Grid end) {                 //准备两个链表,分别存储 将要选择的节点  和  已经走过的节点         ArrayList openlist=new ArrayList();         ArrayList closelist=new ArrayList();                 //将起点加入链表,准备开始寻路。         openlist.add(start);                 //只要链表不为空,就重复这个寻路的过程         while(openlist.size()>0) {                         //找到 openlist中 F值最小的那个 方格(节点)             Grid currentgrid=findMinGrid(openlist);                         //从 openlist中删除找到的那个  F值 最小的那个节点             openlist.remove(currentgrid);                         //将这个  F值 最小的节点,加入到  closelist 中             closelist.add(currentgrid);                         //寻找  当前找到的这个 F值最小的节点的  邻居节点 ——上下左右,四个方向上的节点,要判断它们是否为合法可用的节点。             List neighbors=findNeighbors(currentgrid, openlist, closelist);                         //对合法可用的邻居节点进行初始化,并加入到  openlist中             for(Grid grid : neighbors) {                 if(!openlist.contains(grid)) {                     grid.initGrid(currentgrid,end);                     openlist.add(grid);                 }             }                         //邻居节点加入  openlist 后,判断openlist中,是否包含  终点节点,如果包含终点,直接返回并退出。             for(Grid grid : openlist) {                 if((grid.x==end.x) && (grid.y==end.y)) {                     return grid;                 }             }         }                 return null;     }             //寻找邻居节点的方法,返回值为  链表  ——创建一个合理的邻居链表     private static ArrayList findNeighbors(Grid grid, List openlist, List closelist) {         // TODO Auto-generated method stub                 ArrayList gridlist=new ArrayList();                 //判断上下左右邻居节点的合理性,没问题就加入到邻居链表中。         if(isValidGrid(grid.x, grid.y-1, openlist, closelist)) {//下             gridlist.add(new Grid(grid.x, grid.y-1));         }                 if(isValidGrid(grid.x, grid.y+1, openlist, closelist)) {//上             gridlist.add(new Grid(grid.x, grid.y+1));         }                 if(isValidGrid(grid.x-1, grid.y, openlist, closelist)) {//左             gridlist.add(new Grid(grid.x-1, grid.y));         }                 if(isValidGrid(grid.x+1, grid.y, openlist, closelist)) {//右             gridlist.add(new Grid(grid.x+1, grid.y));         }                         return gridlist;     }       //判断当前位置的节点是否合理     private static boolean isValidGrid(int x, int y, List openlist, List closelist) {         // TODO Auto-generated method stub                 //当前节点是否越界,不再MAZE数组范围内了,注意二位数组的长度计算方法及含意         //MAZE。length表示行的长度         //MAZE[0]。length表示列的长度         if(x=MAZE.length || y=MAZE[0].length) {             return false;         }                 //当前节点是否为障碍节点         if(MAZE[x][y]==1) {             return false;         }                         //判断当前节点是否在 openlist中         if(containgrid(openlist, x, y)) {             return false;         }                 //判断当前节点是否在 closelist中         if(containgrid(closelist, x, y)) {             return false;         }                 return true;     }         //判断当前链表中是否包含当前的节点     private static boolean containgrid(List grids, int x, int y) {         // TODO Auto-generated method stub                 for(Grid grid : grids) {             if((grid.x==x) && (grid.y==y)) {                 return true;             }         }                 return false;     }         //寻找当前链表中的节点F值 最小的那个节点,并返回这个节点。     private static Grid findMinGrid(ArrayList openlist) {         // TODO Auto-generated method stub                 Grid tempgrid=openlist.get(0);         for(Grid grid : openlist) {             if(grid.f


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3