NOTE:修正了一个Bug,加入了能否求解的数学算法判断,代码更新了
算法学的不好,一直没有写什么算法程序。之前一直想写个A*的,研究了一下,最终还没有写成。昨晚花了点时间,用Erlang写了个解八数码的程序,用的是最简单的A*,程序没有做什么优化,中规中矩,偷懒用模式匹配来处理移动情况。如果想看更加优雅的Erlang算法程序,可以查看我在附件提供的sudoku.erl,里面大量使用了高阶函数:)
注意:
0.八数码还是比较简单的,不像华荣道和推箱子那么BT,大部分情况在我的机上都能1s内解决,因此暂时不优化啦。
1.Open Table 和 Closed Table都是用的list,O(N)的查找时间。可以改成O(1)的。
2.这里是一个Tuple为一个Node,{Grid, Weight, Step, ParentStack},每个Node都有自己的ParentStack,占的内存多了些。Erlang里面没有指针,只能这样存值了。我觉得其实就Erlang而言,一个状态节点,为一个Process更加合适,每个Process有Parent Process的引用,这样设计可以利用多核加速,也比较符合Erlang的设计思维。
3.子状态的创建,用了个貌似很“丑陋”的匹配来完成:
move_up({N1,N2,N3,0,N5,N6,N7,N8,N9}) ->
{0,N2,N3,N1,N5,N6,N7,N8,N9};
move_up({N1,N2,N3,N4,0,N6,N7,N8,N9}) ->
{N1,0,N3,N4,N2,N6,N7,N8,N9};
move_up({N1,N2,N3,N4,N5,0,N7,N8,N9}) ->
{N1,N2,0,N4,N5,N3,N7,N8,N9};
move_up({N1,N2,N3,N4,N5,N6,0,N8,N9}) ->
{N1,N2,N3,0,N5,N6,N4,N8,N9};
move_up({N1,N2,N3,N4,N5,N6,N7,0,N9}) ->
{N1,N2,N3,N4,0,N6,N7,N5,N9};
move_up({N1,N2,N3,N4,N5,N6,N7,N8,0}) ->
{N1,N2,N3,N4,N5,0,N7,N8,N6};
move_up(_) ->
illegal_move.
比如这个,表示当0不在第一行(N1-N3)时可以返回一个合法的子状态,我觉得这样做挺方便,虽然丑了些
4.使用"每个不在目标位置上的数字块到目标位置的最少步数之总和"作为H(),层数作为G()
5.下次有空尝试改成IDA算法和Process作为一个Node
代码看附件,顺便带上某高手写的数独解法。