题目描述
要求输入一个拼图的初始状态,返回拼图的成功所经过的最小的步数,例如:
初始状态:
1 2 3
4 5 6
7 0 8
成功的状态
1 2 3
4 5 6
7 8 0
输出步数 : 1
0号可以与相邻的数字进行交换,要求最后的状态0号位于右下方,其余位置按上面的顺序排列
分析
这和我们常见的迷宫求解的题目有些差别,迷宫求解的过程中可以标记走过的路,以防止重复同样的步骤,但这里不能通过标记走过的位置了,因为一个要达到最终的状态,可能一个位置要重复地走很多遍才能达到成功的状态。
虽然不能标记拼图中单独的位置,我们可以把整个地图的状态保存下来,当0位置改变的时候,我们判断改变后的拼图是否已经出现过,如果出现过,0位置不改变,否则才改变。
这里我们采用递归的分析方式,函数findCount(x,y)返回当0位于(x,y)位置时到达成功状态所经过的最小的步数,每次0号位置都有四种移动方案 向上、向下、向左、向右,只要统计出经过四个方向到达成功状态的最小步数,
转换成代码就是
findCount(x,y) = min(findCount(x-1,y),findCount(x,y-1)
, findCount(x+1,y),findCount(x,y+1));
只要找到递归的公式,递归的代码比较容易了。
这里还有一个问题就是怎样保存整个拼图,这个方法有很多,我用了一种hash的方式
//传入保存拼图的数组
int fun(vector<vector<int> > &vec)
{
int tmp = 0;
int row = vec.size();
for(int i = 0; i < row; ++i)
{
int col = vec[i].size();
for(int j = 0; j < col; ++j)
{
int a = vec[i][j] + (i*row+j);
//求解拼图中各个位加上一定的对应的数值后,再向右移动相应的位数,
//这里要尽量保证不同的拼图状态求出的hash 值不相同
tmp += (a << (i*row+j));
}
}
return tmp;
}
代码的完整实现
#include <iostream>
#include <queue>
#include <vector>
#i