大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
学习人工智能这门课历经坎坷,拿到习题集,第一道就开口脆,原题如下:
翻阅AIMA教材无思路,Berlekamp等人的文献不知如何找寻,冥想整日无头绪,遂四方觅得习题集参考答案,还是英文版:
Definition: The goal state has the numbers in a certain order, which we will measure as starting at the upper left corner, then proceeding left to right, and when we reach the end of a
row, going down to the leftmost square in the row below. For any other configuration besides
the goal, whenever a tile with a greater number on it precedes a tile with a smaller number,
the two tiles are said to be inverted.
Proposition: For a given puzzle configuration, let N denote the sum of the total number
of inversions and the row number of the empty square. Then (Nmod2) is invariant under any
legal move. In other words, after a legal move an odd N remains odd whereas an even N
remains even. Therefore the goal state in Figure 3.4, with no inversions and empty square in
the first row, has N = 1, and can only be reached from starting states with odd N, not from
starting states with even N.
Proof: First of all, sliding a tile horizontally changes neither the total number of inversions nor the row number of the empty square. Therefore let us consider sliding a tile
vertically.
Let’s assume, for example, that the tile A is located directly over the empty square.
Sliding it down changes the parity of the row number of the empty square. Now consider the
total number of inversions. The move only affects relative positions of tiles A, B, C, and D.
If none of the B, C, D caused an inversion relative to A (i.e., all three are larger than A) then
after sliding one gets three (an odd number) of additional inversions. If one of the three is
smaller than A, then before the move B, C, and D contributed a single inversion (relative to
A) whereas after the move they’ll be contributing two inversions – a change of 1, also an odd
number. Two additional cases obviously lead to the same result. Thus the change in the sum
N is always even. This is precisely what we have set out to show.
So before we solve a puzzle, we should compute the N value of the start and goal state
and make sure they have the same parity, otherwise no solution is possible.
一眼看去,使用局面逆序数与空格所在行数的和作为划分八数码问题两大互补集合的依据合乎情理,精妙至极,然而细细推敲之下,总不知道Solution中A牵扯到的B、C、D究竟代表了什么。我在草纸上一遍遍推演着,每一次出现推理矛盾都加深了我想要彻底搞清楚这个谜题的想法。
描绘八数码问题:
在3*3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为012345678),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
而在实际的众多备选搜索局面中,有一些局面无法通过当前局面到达,这就引出了这道证明题,先是要求描绘什么样的局面可以到达,再描绘什么样的局面无法到达。
判断某个局面是否可达:
将八数码问题向量化,则某一个局面可以用包含9个分量的一维向量描绘,如(0, 1, 2,…, 8)是一种局面,其中0表示空格, k表示数字k。对于某一局面忽视0,对从1到8这八个数字排成的序列求逆序数称为局面逆序数A。如果两个局面的逆序数A的奇偶性不同,则两个局面无法互相达到。在任意一行中交换空格和(左右)相邻的数字,交换前后的局面中逆序数A不变。在任一列中交换空格和(上下)相邻的数字,则对于8数码问题而言,相当于将局部排列(A,B,C)变为(B,C,A),等价于两次交换(AB,然后AC),前后局面的逆序数奇偶性不发生改变。所以,无论怎么移动空格,局面的奇偶性不会发生改变。
使用计算局面逆序数的方式可以判断一个给定的状态是哪个子集,只需要A%2即可。
在生成随机状态时,不生成无法到达的局面可以更快地搜索出结果。
然而我不禁思考,同一集合中的局面一定能通过有限步骤够互相转换吗?最直观的局面是(1,2,0,3,4,5,6,7,8)与局面(1,2,3,0,4,5,6,7,8)如何转化?如果是更复杂更打散的局面呢?有没有算法可以不使用搜索而直接计算出解法呢?
规范化证明问题为:所有的奇九宫图(局面逆序数A为奇数)之间是可达的,所有的偶九宫图之间也是可达的,但奇九宫图和偶九宫图之间互不可达。
为了证明上述命题,需要先对问题进行一下转化。定义两种行序列的变换:一种
是空格0和相邻的数对换,一种是空格0和前后隔两个数的数之间的对换,前者对应着空格在九宫图中的左右移动,后者对应着空格在九宫图中的上下移动。
在上述的两种对换下,序列的奇偶性不改变。这个引理很容易证明。 首先,相邻的对换肯定不改变奇偶性;其次,隔两格的对换也不改变奇偶性,它相当于三个数的轮换,这一点在“判断某个局面是否可达”的环节已经解决了,它说明了奇九宫图和偶九宫图之间是互不可达的。
所有的奇状态可以转换为 (0,1,2,3,4,5,6,7,8)。
所有的偶状态可以转换为 (0,2,1,3,4,5,6,7,8)。
要证明这个引理,得分几个步骤。先设法把8移到最后一个,然后8保持不动(然而这里的不动只是形式上不动,但不管怎样,我们的每一个变换后,8还是保持在最后一个,余类似),再将7移到8之前,然后保持7和8不动,依次移动6,5,4,3,得到(*,*,*,3,4,5,6,7,8)这里(*,*,*)是(0,1,2)的一个排列。到这里,我想要得到前面的两种状态之一是显然的了。对于(a,b,c,0) ,可以将其中的任意一个移到最后,并且对变换仅限于这四个位置上。显然,对于a是一步就可以做到的。对于b, 步骤如下:
(a,b,c,0) –> (0,b,c,a)–>(b,0,c,a)–>(b,c,0,a)–>(b,c,a,0) –> (0,c,a,b)
对于c的移动方法类似地可以模板化实现,具体实现的路径可能有很多种,借用搜索节点与状态描述的概念,这里就不再赘述。
理论上,先把要移到最后位置的那个数移到最后四个位置之一,然后再将空格移到最后一个位置,用(a,b,c,0)作为局部初始状态的方法将待移动的数变换到最后一个位置。循环这样做就可以按照循环的方式实现局面移动,不过这并不是步数最少的方案。
说到步数最少,在搜索法中,广度优先搜索法是寻找最短路经的首选。
广度优先搜索算法的基本步骤:1)建立一个队列,将初始结点入队,并设置队列头和尾指。2)取出队列头(头指针所指)的结点进行扩展,从它扩展出子结点,并将这些结点按扩展的顺序加入队列。3)如果扩展出的新结点与队列中的结点重复,则抛弃新结点,跳至第六步。4)如果扩展出的新结点与队列中的结点不重复,则记录其父结点,并将它加入队列,更新队列尾指针。5)如果扩展出的结点是目标结点,则输出路径,程序结束。否则继续下一步。6)如果队列头的结点还可以扩展,直接返回第二步。否则将队列头指针指向下一结点,再返回第二步。然后是搜索路径的输出:搜索到目标结点后,需要输出搜索的路径。每个结点有一个数据域last,它记录了结点的父结点,因此输出搜索路径时,就是从目标结点Q出发,根据last找到它的父结点,再根据这个结点的last找到它的父结点,….,最后找到初始结点。搜索的路径就是从初始结点循相反方向到达目标结点的路径。
然而八数码问题具有可逆性,也就是说,如果可以从一个状态A扩展出状态B,那么同样可以从状态B扩展出状态A,这种问题既可以从初始状态出发,搜索目标状态,也可以从目标状态出发,搜索初始状态。对这类问题如果采用双向广度优先搜索法,将可以大大节省搜索的时间。所谓双向广度优先搜索法,是同时从初始状态和目标状态出发,采用广度优先搜索的策略,向对方搜索,如果问题存在解,则两个方向的搜索会在中途相遇,即搜索到同一个结点。将两个方向的搜索路径连接起来,就可以得到从初始结点到目标结点的搜索路径。广度优先搜索法搜索时,结点不断扩张,深度越大,结点数越多。如果从两个方向向对方搜索,就会在路径中间某个地方相会,这样,双方的搜索的深度都不大,所搜索过的结点数就少得多,搜索时间也就节省不少。
对于双向广度优先搜索法,如何判断两个方向的搜索相遇呢?只要我们在生成结点的同时,判断该结点是否出现在相反方向的搜索树上即可,也就是说,在某个方向搜索中扩展出一个新结点,如果它与另一个方向已扩展出的结点重复,也就找到了解。这让我联想到之前都往初始状况搜索的算法,果然是有利有弊,牺牲了步数就可以换取稳定解,使用循环实现递归,每次确定一个数字的最终位置,倒还与冒泡排序有几分相像。
既然学习了启发式算法,搜索效率自然是要高于盲搜的,重点在于耗散函数的选取,对于八数码问题,可以认为h=1/t,其中t是当前已经占据正确位置数码的个数。
这题研究了这么久,8数码终于心中有数了,只是心中还有个小小的疑问,以后再解决吧:4*4格的数码问题中,为什么是N的奇偶性保持不变呢,这和8数码的分集合描绘有着什么奇怪的联系呢?
参考文献:
[1]付宏杰,王雪莹,周健,周孙静,朱珠,张俊余.八数码问题解法效率比较及改进研究[J].软件导刊,2016,15(09):41-45.
[2]李健,赵盼.一种求解N阶数码问题的通用算法[J].现代计算机(专业版),2014(14):26-30.
[3]周浩.八数码问题DFS和BFS算法的设计与实现[J].电脑知识与技术,2011,7(22):5487-5489.
[4]廖鸿志,曹仲.一种基于八数码问题的改进算法[J].现代计算机(专业版),2010(07):32-33+63.
[5]闵文杰.十五数码问题研究及实现[J].福建电脑,2010,26(02):73-74.
[6]张鸿.人工智能中求解八数码问题算法的实现与分析[J].软件导刊,2009,8(06):62-64.
[7]AIMA(3rd) Solution,https://download.csdn.net/download/yangdong500239/10274028
[8]八数码问题解析, http://www.cnblogs.com/whyaza/archive/2018/09/20/9683587.html
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/158885.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...