实验任务
实验要求
在3×3九宫棋盘中,放置数码为1~8的8个棋子,棋盘中留一个空格,空格周围的棋子可以移动到空格中,从而改变棋盘布局
根据给定初始布局和目标布局,移动棋子从初始布局达到目标布局,求解移动步骤并输出。
需求分析
这个项目主要涉及到两个知识点,九宫重排问题和A*算法
九宫重排问题
九宫重排问题可以理解为华容道的简化版,空格能与其周围上下左右的数字交换,每次交换后都会改变棋盘布局,最终能达到目标状态即可,但到达目标状态的路径可能有多重,我们需要找寻最短路径
A*算法
算法本质是
其中:
- f(n)是节点n的综合优先级。当我们选择下一个要遍历的节点时,我们总会选取综合优先级最高(值最小)的节点。
- g(n) 是节点n距离起点的代价。
- h(n)是节点n距离终点的预计代价,这也就是A*算法的启发函数。
除了这三个数值外,结点还需要包含一个属性,那就是来源,只有通过此属性才能确定g值,当前结点的g值=父节点g+到此节点距离代价,此外,在到达终点后,通过来源属性倒推回起点,实现完整的寻路
A* 算法用两个集合open_set和close_set存储待遍历节点和已遍历节点
A* 算法每次在选取结点时,都会选择待遍历结点中f(n)较小的节点进行操作
相关文章csdn都有很多详解,我就不一一赘述了
系统设计
分三个板块,接收系统、运算系统、显示系统
接收系统
接受用户传递数字排列方式,并通过显示系统在命令行输出初始状态
运算系统
采用A* 算法,通过判定空格所在位置上、下、左、右格子的f值,选择f值最小的数字进行交换
不同于常规使用的A* 算法
常规使用的时候,A* 算法close_set内存储的是已经走过的全部结点
但此处的A*算法close_set里面的值只有一个,就是刚刚走过的父节点,因为空格还是会经过曾经的位置,但那里已经存储的不是当初的数值了,其终点代价会改变
正应为这个缘故,所以此时路径就不是常规的根据父节点找回起点,可以设立一个数组专门存储行走路径
g(n)的选取
g是行动代价,我初始的想法是可以取消,毕竟空格周围任意一个数字的移动行动代价都是1,每次都是叠加1,没有优劣可分
但这个想法应该是简陋的,最快到达终点的衡量尺度正是这一数值,其在某些可能的死循环情况下(例如移动数字后和移动前h值一样)能够让我们跳出来
h(n)的选取
我想到有2种评判标准
- 不在自己位置的数字个数
- 各数字到达自己位置的距离即曼哈顿距离
我选择的是前者,后者为传统A* 算法的判定标准,但在移动数字问题上,各数字是不能自由移动的,而且和空格交换完位置就无法进一步移动,那么距离标准就毫无意义
显示系统
根据传递进来的二维数组,在命令行输出显示,给用户看行动路径
小结
通过本次预习,认真查阅了九宫重排问题和A* 算法的相关资料
大概了解到九宫重排问题的几种解决算法
无论是广度优先还是深度优先其本质上都是盲目搜索
虽然在九宫重排问题上有的时候会找到比A* 算法更快的方式
但当移动次数增多后,其运算的时间代价是近乎指数型的在增长,不是长久之计
A* 算法作为启发式搜索还是有很多值得探索的地方,日后需深入研究