八数码问题——九宫格华容道求解
我们要对华容道问题求解首先要判断这个问题是否有解。这里我们给出以下结论
数字华容道,必然有解,只存在于如下3个细分情形:
1.若格子列数为奇数,则逆序数必须为偶数;
2.若格子列数为偶数,且逆序数为偶数,则当前空格所在行数与初始空格所在行数的差为偶数;
3.若格子列数为偶数,且逆序数为奇数,则当前空格所在行数与初始空格所在行数的差为奇数。
转自:https://www.jianshu.com/p/1c1849d876b2
当我们判断我们的输入有解后我们采用A*算法求解。
A*算法的核心可以用一个函数来表示 f(n)=g(n)+h(n)
其中g(n)表示我们实际的损失,具体的在这里表示我们目前已经走了几步,这个是非常具体的,因为你走了几步就是几步。
h(n)表示的是我们预估我们从目前的状态到达目标的状态的损失的一个函数h,这是我们人为设定的,而对于所有的情况我们都只能通过我们设定的这一个函数h来预算,意思就是我们在第1步的时候通过一个确定的函数h来计算损失,那么第2步我们也只能通过这个函数h来计算损失,不能改变这个函数h。由于函数h是我们认为设定的,所以我们设定的函数h往往决定了我们得到结果的快慢。
我们的目标是用尽量少的步数来得到结果123 456 780,0表示没有数字的格子。
当我们得到了一个输入后,我们可以有四个选择,即让0与上下左右位交换(当然是要考虑越界,也就是碰墙的情况),对于得到的结果我们计算f(n),之后我们总是寻找一个最小的f(n)来拓展节点直到我们得到目标函数或者无解(其实就是找遍了所有的可能都找不到解)。而对于起始输入以及拓展后不属于已经计算过的结果我们加入open表,对于已经计算过的结果我们放入close表,之前说到的寻找最小的f也是在open表中寻找。
下面来试着从输入到输出开始说起,我们得到一个输入,我们输入放入open表,计算open表中损失f最小的节点,我们拓展该节点,将原始结点移出open表放入close表,对于拓展的节点我们判断其是否是结果,若不是则判断其是否已在close表,若没有在close表,我们判断其知否在open表,若不在open表中我们就将其加入到open表,若在open表就不加入(无需判断,因为我们总是从最小的step出发,在h(n)相同的情况下,首先出现的肯定是最小的step)。之后我们寻找open表中损失f最小的节点,重复上面的操作就能得到结果。(这里忽略了一开始就是最终解的情况,实际上我们需要判断输入是否已经是最终解)
由于网上找不到目标是123 456 780的图,故这里给出的是目标是123 804 765的图(仅供参考,思路是一样的)
因为是很久以前完成的小程序了,以前只懂python,所以这里只给出python版
输入规则例子:按回车426按回车153按回车780
github:https://github.com/a892574222/Artificial-Intelligence/tree/master/Eight%20Puzzles