A*
P1379华容道
问题是要从初始布局用最少的步骤到目标布局,每次只能动0周围的格子,就是华容道;
怎么用算法的思路解决?
状态压缩思路
每个数字就代表当前的状态,队列和map函数都记录的是当前的状态数,
描述一个状态有矩阵形式也有一个数形式
这里c[3][3]是描述状态的矩阵,n就是描述状态的数
这里是把n转化为矩阵形式,并且得到矩阵中0的位置,用f,g记录
执行交换操作无法在数中执行,比较抽象,所以是要转为矩阵,在矩阵里尝试交换,交换完后再转回数的形式进行存储,就是为了节约空间,ns是当前矩阵按当前遍历次序移动完后的结果,
如果在Map里没有出现,就是Map里没有这个数(这个状态),就意味着是新到的状态,由于是bfs,所以必定是到达这个状态的最小步数
#include
#include
map
map查找
map操作函数
常用的count(),返回的是出现次数,int型,返回的是键的出现次数,不是键对应的值,所以只可能是0或者1
如果是!m.count(n)就表示是没有找到时触发,即此时map里还没有n这个键
m.count(n)就表示找到了这个元素,即map里此时已经有了n这个元素
A*方法
这一步是在判断当前状态是否还有可能是解,step是当前步数,cnt是估价函数值,cnt的值的确定,是有双重循环,一检测到当前格子里的和解里的不一样,就会++cnt,这循环9次,或者在循环里时就超过限制,就退出了
这个就是判断当前是不是解
就是说pre是记录上一次到这里来时的方向标号,就意味着不应该再走回去,如果走回去的话,就是先向上(下)走再向下(上)走,先向左(右)走再向右(左)走
可以人为定义状态移动数组,从而满足相反方向的序号具有一定关系
这里是使用对称数组排列,从而使相反方向的序号加和为数组长度-1
所以在递归判断中,是要判断pre+i==3,pre是上一个方向,i是这次选择的方向,加起来为3就是走了回去,需要被剪掉
这个操作虽然不能避免死循环的诞生,比如回字型循环,或者重复状态的出现(避免了只需两步的重复状态,但可能多步回到初始位置),但依然可以避免大量的两步重复
这里是将输入的字符串(状态压缩的序列)转为矩阵,并得到0的位置
是把K作为外层循环,即直接建立在步数限制的基础上判断当前是不是能到达
#include
#include
#include