1.从起点 开始,把它加入到一个由方格组成的open list(开放列表) 中,这个open list像是一个购物清单。Open list里的格子是可能会是沿途经过的,也有可能不经过。因此可以将其看成一个待检查的列表。查看与相邻的8个方格 ,把其中可走的 (walkable) 或可到达的(reachable) 方格加入到open list中。并把起点 设置为这些方格的父节点 (parent node) 。然后把 起点 从open list中移除,加入到close list(封闭列表) 中,close list中的每个方格都是不需要再关注的。
2.需要从open list中选一个与起点相邻的方格。但是到底选择哪个方格好呢?选F值(F(n) = G + H 。G代表的是从初始位置A沿着已生成的路径到指定待检测格子的移动开销。H指定待测格子到目标节点B的估计移动开销。H采用的是传统的曼哈顿距离(Manhattan Distance),也就是横纵向走的距离之和,并且忽略沿途的障碍。)最小的那个。
3.比较open list中节点的F值后,发现起点右侧节点的F=40,值最小。选作当前处理节点,并将这个点从Open List删除,移到Close List中。
4.对这个节点周围的8个格子进行判断,若是不可通过(比如墙,水,或是其他非法地形)或已经在Close List中,则忽略。否则执行以下步骤:
5.(1)若当前处理节点的相邻格子已经在Open List中,则检查这条路径是否更优,即计算经由当前处理节点到达那个方格是否具有更小的 G值。如果没有,不做任何操作。相反,如果G值更小,则把那个方格的父节点设为当前处理节点 ( 我们选中的方格 ) ,然后重新计算那个方格的 F 值和 G 值。(2)若当前处理节点的相邻格子不在Open List中,那么把它加入,并将它的父节点设置为该节点。
算法思想:
1.定义open表和close表,其中open表是用来存储待查验的节点,而close表是用来存储已查验过的节点(不需要再关注的节点)
2.把开始节点加入open表;
3.将开始节点拓展的子节点加入open表,将开始节点加入到close表;
4.将open表中的节点的耗散值也就是f进行从小到大的排序,此时open表中的第一个节点的耗散值最小,对open表中的第一个节点进行判断,如果这个节点是目标节点,则算法结束,无需进行以下步骤;反之,如果这个节点不是目标节点,则将这个节点进行扩展,再进行下一步;
5.判断n的可扩展节点(相邻节点)m,情况一:如果m在open表中,则说明初始节点到m节点出现了两条路径,此时需要判断这两条路径的耗散值的大小如果是新路径的耗散值小,则需要更改m节点的父节点,并将open表中的原的m节点加入close表,将现在的m节点加入open表,如果是新路径的耗散值大,则不需要进行任何操作;情况二:如果m在close表中,则说明初始节点该节点到m节点有两条路径,如果是新路径的耗散值大,则不需要进行任何操作如果是新路径的耗散值小,需要将更改m节点的父节点,并将m节点从close表中取出,并放入open表中;情况三:m节点既不在open表中也不在close表中,直接将m节点加入到open表中即可;
6.重复第4步,(算法结束的两种情况,其一,当前节点就是目标节点,即找到
了最优解;其二,open表为空,既无法找到到目标节点的路径,即无解。)
首先通过构建结点类,存储上下左右四个方向的状态,并用parent结点记录其原来位置,通过A算法的需要,构建评估价值的函数,即F(n)=g(n)+h(n)
其次构建隐式图的主要运作类
1.对是否可行的判断(奇偶性判断)放在一开始,若不可行,即不能到达目标位置,则直接,跳过。
2.构建判断两个二维数组是否相等的函数,作为结束的判断,以及中间查重的步骤。
3.构建g(n)函数,即两个二维数组有多少数字不相同。
4.构建主要的运行函数,通过对于四个方向的判断,增添其子节点。通过循环不断添加,直到达到目标位置。
5.输出函数,逆序输出,从到达的目标位置,不断寻找父结点存到一个新的列表里。
F(n)函数用于对列表再排序,找到价值最大的结点,寻找他的子节点。
实验任务:
1)对九宫重排问题,建立图的启发式搜索求解方法;
2)用A算法求解九宫重排问题。
实验要求:
3х3九宫棋盘,放置数码为1~8的8个棋子,棋盘中留有一个空格,空格周围的棋子可以移动到空格中,从而改变棋盘的布局。根据给定初始布局和目标布局,移动棋子从初始布局到达目标布局,求解移动步骤并输出。请设计算法,使用合适的搜索策略,在较少的空间和时间代价下找到最短路径。
编程语言以及开发环境的选择
编程语言采用java,开发环境为idea
实验思路
对于8数码问题我们首先应该想到的是问题是否可解,如何判断呢?这里给出如下判定结论:
将状态表示成一维的形式,求出除0(空格)之外所有数字的逆序数之和,也就是每个数字前面比它大的数字的个数的和,称为这个状态的逆序数。若两个状态的逆序奇偶性相同,则可相互到达,否则不可相互到达[1]。
例如:
S0表示成: 2 X 3 1 8 4 7 6 5
则:f(2)=0, f(3)=0, f(1)=2, f(8)=0, f(4)=1, f(7)=1, f(6)=2, f(5)=3
Sg表示成: 1 2 3 8 X 4 7 6 5
则:f(2)=0, f(3)=0, f(1)=2, f(8)=0, f(4)=1, f(7)=1, f(6)=2, f(5)=3
当f(a8)+f(a7)+……+f(a1)均为奇数或偶数时才能重排成功,所以,S0到Sg状态有解。
判断是否可解的问题解决了,用什么样的搜索算法找到移动路径呢?
其实,不管哪种搜索,都可以统一用这样的形式表示: 搜索的对象是一个图,它面向一个问题,不一定有明确的存储形式,但它里面的每一个结点都有可能是一个解(可行解),搜索的目的有两个方面,或者求可行解,或者从可行解集中求最优解。
搜索算法可分为两大类:无信息的搜索算法和有信息的搜索算法。无信息的搜索又称盲目搜索,其特点是只要问题状态可以形式化表示,原则上就可用使用无信息的搜索,无信息搜索有如下常见的几种搜索策略:广度优先搜索、代价一致搜索、深度优先搜索、深度有限搜索、迭代深入优先搜索、双向搜索。我们说DFS和BFS都是蛮力搜索,因为它们在搜索到一个结点时,在展开它的后续结点时,是对它们没有任何‘认识’ 的,它认为它的孩子们都是一样的‘优秀’,但事实并非如此,后续结点是有好有坏的。好,就是说它离目标结点‘近’,如果优先处理它,就会更快的找到目标结点,从而整体上提高搜索性能。
为了改善上面的算法,我们需要对展开后续结点时对子结点有所了解,这里需要一个估值函数,估值函数就是评价函数,它用来评价子结点的好坏,因为准.确评价是不可能的,所以称为估值。这就是我们所谓的有信息搜索。如果估值函数只考虑结点的某种性能上的价值,而不考虑深度,比较有名的就是有序搜索(Ordered-Search),它着重看好能否找出解,而不看解离起始结点的距离(深度)。如果估值函数考虑了深度,或者是带权距离(从起始结点到目标结点的距离加权和),那就是A*。简单的来说A*就是将估值函数分成两个部分,一个部分是路径价值,另一个部分是一般性启发价值,合在一起算估整个结点的价值。