UVa1601 Morning after holloween 解题分析
只有思路还没有实践
这个题一眼看上去就是典型的状态空间搜索问题,a,b,c的每一个不同摆放位置都是一个状态,每一个状态都可以看成无权有向无环状图上的一个节点。又是找移动步数最少的走法,很自然就会想到用BFS。
细想上去,这个题稍微麻烦的地方是,如何从一个状态扩展到下一个状态。每个状态有2个或者3个字母需要考虑。如果是3个字母,似乎应该用一个三重循环来枚举每个字母的5种移动方向,上下左右和不动,跑去3个字母都不动的情况,这样一共5*5*5-1=124种!但最后真正能合法压入BFS队列的可能很少。
那么重124种候选状态中那些是合法的?需要做如下判断
1)字母不能摆出图形的边界
2)字母不能摆在障碍上
3)两个或三个字母摆在同一个位置上。
4)任意两个字母的新位置不能由这两个字母的上一个位置对调而得来。
5)形成的状态不能是以前处理过的状态
这四项判断应该能筛除掉大部分的备选状态。
要进行这四项判断,必须有一个数据结构来保存原始的底图,用二维数组来标明,哪个位置有障碍,哪个位置可以摆放。这个图的长宽要保留下来做是否出界的判断。还要有一个数据结构用来保留已经处理过的状态,确保不重复处理同一个状态,这个数据结构应该是个hash的结构,现在还没想好怎么做。
题目要求打印需要最少的步数,那么每一个状态中应该有一个数据用来保存这个状态是在第几步产生的。查询的结束条件有两个:一个是找到的状态和目标状态完全一致,那么查找成功;一个是所有的状态全部处理完毕,BFS队列全空,说明没有一条路径可以到达目标状态。
原题中要移动的字母也可能只有a,b两个,它的子集和排列都少很多,要尝试的下一个状态也少很多,但是这个变化稍稍增加了题目的复杂度。还好这题只是要打印步数,如果要打印路径,那就更麻烦,在每一个已处理过的状态中要有一个指针指向上一个状态。最后在倒着把这个列表打出来。一个状态可以扩展出很多子状态,但是每个子状态只有一个父状态。
这个题的思路就是这样的,标准的状态空间搜索,就是条件太多,写起来是个力气活儿,调起来更是不敢想, 现在有点懒得写,不知道还有没有更好的方法,要不要真的这么麻烦?