八数码问题分析班级:计算机1041学号:01*名:***2013年9月26日摘要八数码问题(Eight-puzzle Problem )是人工智能中一个很典型的智力问题。
本文以状态空间搜索的观点讨论了八数码问题,给出了八数码问题的Java 算法与实现的思想, 分析了A*算法的可采纳性等及系统的特点。
关键词 九宫重排, 状态空间, 启发式搜索, A*算法1 引言九宫重排问题(即八数码问题)是人工智能当中有名的难题之一。
问题是在3×3方格盘上,放有八个数码,剩下一个位置为空,每一空格其上下左右的数码可移至空格。
问题给定初始位置和目标位置,要求通过一系列的数码移动,将初始状态转化为目标状态。
状态转换的规则:空格周围的数移向空格,我们可以看作是空格移动,它最多可以有4个方向的移动,即上、下、左、右。
九宫重排问题的求解方法,就是从给定的初始状态出发,不断地空格上下左右的数码移至空格,将一个状态转化成其它状态,直到产生目标状态。
图1许多学者对该问题进行了有益的探索[1,2,4,6]。
给定初始状态,9个数在3×3中的放法共有9!=362880种,其状态空间是相当大的。
因此, 有必要考虑与问题相关的启发性信息来指导搜索,以提高搜索的效率。
当然,还有个很重要的问题:每个初始状态都存在解路径吗?文献给出了九宫重排问题是否有解的判别方法:九宫重排问题存在无解的情况,当遍历完所有可扩展的状态也没有搜索到目标状态就判断为无解。
可以根据状态的逆序数来先验的判断是否有解,当初始状态的逆序数和目标状态的逆序数的奇偶性相同时,问题有解;否则问题无解。
状态的逆序数是定义把三行数展开排成一行,并且丢弃数字 0 不计入其中,ηi 是第 i 个数之前比该数小的数字的个数,则 η=Σηi 是该状态的逆序数,图2说明了逆序数计算的过程 。
本文介绍用JAVA 编写九宫重排问题游戏。
游戏规则是,可随机产生或由用户设置初始状态,由初始状态出发,不断地在空格上下左右的数码移至空格,若能排出目标状态,则成功。
为了避免对无解节点进行无用搜索,首先对初始节点进行逆序数分析,对有解的节点进行搜索,从而节省了资源,也提高了效率。
本文内容安排: 第2部分介绍几个相关的概念和A*算法以及可采纳性;2 A*算法2.1 相关的概念定义1:状态:是描述问题求解过程中任一时刻状况的数据结构,一般用一组变量的有序组合表示:Sk=(Sk0,Sk1,…)当给每一个分量以确定的值时,就得到了一个具体的状态。
定义2:算符:引起状态中某些分量发生变化,从而使问题由一个状态变为另一个状态的操作称为算符。
定义3:状态空间:由问题的全部状态及一可用算符所构成的集合称为问题的状态空间。
一般用一个三元组表示:(S,F,G)。
其中,S是问题所有初始状态的集合,F是算符的集合,G是问题所有目标状态的集合。
定义4:状态空间图:状态空间的图示形式称为状态空间图,其中,节点表示状态,有向边表示算符。
状态空间搜索的基本思想就是通过搜索引擎寻找一个操作算子的调用序列,使问题从初始状态变迁到目标状态之一,而变迁过程中的状态序列或相应的操作算子调用序列称为从初始状态到目标状态的解路径。
搜索引擎可以设计为任意实现搜索算法的控制系统。
2.2 A*算法以及可采纳性A*算法是一个很重要的启发式搜索算法。
如果一般图搜索过程进行如下限制,则它就成为A*算法:(1)把OPEN表中的节点按估价函数f(x)= g(x)+h(x)的值从小到大进行排序;(2) g(x)是对g*(x)的估计,g(x)0;(3) h(x)是h*(x)的下界,即对所有的x均有:h(x)≤ h*(x)其中,g*(x)是从初始节点到节点x 的最小代价,h*(x)是节点x到目标节点的最小代价,若有多个目标节点,则为其中最小的一个。
定义5:算法的可采纳性(Admissibility)一般来说,对任意一个状态空间图,当从初始节点到目标节点有路径存在时,如果搜索算法能在有限步内找到一条从初始节点到目标节点的最佳路径,并在此路径上结束,则称该搜索算法是可纳的。
A*算法是可纳的,即它能在有限步内终止并找到最优解。
我们分三步用以下三个定理来证明这一结论[1,2]。
定理1:对有限图,如果从初始节点S0到目标节点Sg有路径存在,则算法A*一定成功结束。
证明:首先证明算法必定会结束。
由于搜索图为有限图,如果算法能找到解,则会成功结束;如果算法找不到解,则必然会由于Open表变空而结束。
因此,A*算法必然会结束。
然后证明算法一定会成功结束。
由于至少存在一条由初始节点到目标节点的路径,设此路径S0= n0,n1 ,…,nk =Sg算法开始时,节点n0在Open表中,而且路径中任一节点ni离开Open表后,其后继节点ni+1必然进入Open表,这样,在Open表变为空之前,目标节点必然出现在Open表中。
因此,算法必定会成功结束。
引理1:对无限图,如果从初始节点S0到目标节点Sg有路径存在,且A*算法不终止的话,则从Open表中选出的节点必将具有任意大的f值。
证明:略。
引理2:在A*算法终止前的任何时刻,Open表中总存在节点n’,它是从初始节点S0到目标节点的最佳路径上的一个节点,且满足:f(n’) ≤ f*(S0)证明:略。
定理2对无限图,若从初始节点S0到目标节点t有路径存在,则A*算法必然会结束。
证明:(反证法)假设A*算法不结束,又引理1知Open表中的节点有任意大的f值,这与引理2的结论相矛盾,因此,A*算法只能成功结束。
定理3:A*算法是可采纳的,即若存在从初始节点S0到目标节点Sg的路径,则A*算法必能结束在最佳路径上。
证明:证明过程分以下两步进行:先证明A*算法一定能够终止在某个目标节点上。
由定理1和定理2可知,无论是对有限图还是无限图,A*算法都能够找到某个目标节点而结束。
再证明A*算法只能终止在最佳路径上(反证法)。
假设A*算法未能终止在最佳路径上,而是终止在某个目标节点t处,则有f(t)=g(t)f*(S0)但由引理2可知,在A*算法结束前,必有最佳路径上的一个节点n’在Open 表中,且有f(n’) ≤ f*(S0)f(t),这时,A*算法一定会选择n’来扩展,而不可能选择t,从而也不会去测试目标节点t,这就与假设A*算法终止在目标节点t相矛盾。
因此,A*算法只能终止在最佳路径上。
4.广度优先搜索法的缺点广度优先搜索法在有解的情形总能保证搜索到最短路经,也就是移动最少步数的路径。
但广度优先搜索法的最大问题在于搜索的结点数量太多,因为在广度优先搜索法中,每一个可能扩展出的结点都是搜索的对象。
随着结点在搜索树上的深度增大,搜索的结点数会很快增长,并以指数形式扩张,从而所需的存储空间和搜索花费的时间也会成倍增长。
5.双向广度优先搜索法1.双向广度优先搜索法八数码问题具有可逆性,也就是说,如果可以从一个状态A扩展出状态B,那么同样可以从状态B扩展出状态A,这种问题既可以从初始状态出发,搜索目标状态,也可以从目标状态出发,搜索初始状态。
对这类问题如果采用双向广度优先搜索法,将可以大大节省搜索的时间。
所谓双向广度优先搜索法,是同时从初始状态和目标状态出发,采用广度优先搜索的策略,向对方搜索,如果问题存在解,则两个方向的搜索会在中途相遇,即搜索到同一个结点。
将两个方向的搜索路径连接起来,就可以得到从初始结点到目标结点的搜索路径。
2.双向广度优先搜索算法双向广度优先搜索算法的基本步骤如下:1)建立两个队列,一个是正向搜索的队列,另一个是反向搜索的队列。
将初始结点放入正向队列,将目标结点放入反向队列,并设置两个队列的头和尾指针。
2)从正向队列取出队列头(头指针所指)的结点进行扩展。
3)如果扩展出的新结点与队列中的结点重复,则抛弃新结点,跳至第六步。
4)如果扩展出的新结点与队列中的结点不重复,则记录其父结点,并将它加入队列,更新队列尾指针。
5)检查扩展出的结点是否在另一方向的队列中,如果是则两个方向的搜索相遇,显示搜索路径,程序结束。
否则继续下一步。
6)如果队列头的结点还可以扩展,直接返回第二步。
否则将队列头指针指向下一结点,然后对另一方向搜索的队列,按照第二步开始的同样步骤处理。
3.双向广度优先搜索法的优势广度优先搜索法搜索时,结点不断扩张,深度越大,结点数越多。
如果从两个方向向对方搜索,就会在路径中间某个地方相会,这样,双方的搜索的深度都不大,所搜索过的结点数就少得多,搜索时间也就节省不少。
从理论上说,如果每一结点可扩展的子结点数为m,广度优先搜索的搜索树就是一颗m叉树,也就是每个结点都由m个分支。
按完全m叉树计算,如果目标结点在第n层,广度优先搜索就必须在搜索树上扩展完n-1层的所有结点,扩展的结点数为m(mn-1)/(m-1)。
对于双向广度优先搜索来说,如果两个方向的搜索在第i层生成同一子结点,那么正向搜索扩展的结点数为m(mi-1)/(m-1),反向搜索扩展的结点数为m(mn-i-1)/(m-1),搜索的结点总数为m(mi+mn-i-1)/(m-1)(其中n是最优解路径长度,i=(m+1) div 2,)。
设n为偶数(n=2*i),广度优先双向搜索扩展的结点数约是广度优先搜索的2/(mi/2+1)*100%,相对减少(mi/2-1)/(mi/2+1)*100%。
4.判断两个方向的搜索相遇在双向广度优先搜索法中,如何判断两个方向的搜索相遇呢?只要我们在生成结点的同时,判断该结点是否出现在相反方向的搜索树上即可,也就是说,在某个方向搜索中扩展出一个新结点,如果它与另一个方向已扩展出的结点重复,也就找到了解。