

我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
123.46758
46758123.
涉及知识点:广度搜索BFS,哈希表
题目已知初态和终态,在初态到终态的过程中,会经过数个不同的状态,一个状态可以通过将空格朝上、下、左、右四个方向移动转移到另一个状态,这是不是有点像搜索找路?题目要求的是“最少移动多少步”,也就是最短距离,求最短距离的办法一般就很容易联想到迪杰斯特拉、广度搜索。这题在像是一个搜索题的前提下,我们就应该选用广度搜索来做。
这题我们把每一个状态看成一个节点,由一个状态到另一个状态是在搜索树上向下了一层。我用queen[MAX]作为广度搜索中用到的队列,用0表示输入的.。队列里的每个元素存储0~8九个数,用queen[i][9]记录当前节点是在搜索树上的第几层,初态是第0层,每多一层表示步数加一。
每个状态可以用一个唯一的数来表示,当状态的表示数与终态相同时,表示已经找到最短路径。表示的方式是,例如样例输入中的终态是123.46758,就记为int型数123046758。这题还需要记录到某个状态是否已经出现过,如果已经出现过就不要再加入队列进行BFS.这里我们用到哈希表,当一个状态要加入到队列前,先判断该状下的表示数是否在已经标记为搜索过,在哈希表hash[]中标记为true的元素表示为已经搜索过。用上述的方法表示的数的范围是12345678~9876543210,如果哈希表的空间开辟到9876543210这么大的话会超过限制。由于已知一个状态必然是9位数(包括0),用八位数就可唯一的表示出每个状态。小于12345678的数不会出现,所以把表示每个状态的数减去12345678,形成最终在程序里用到的表示状态的数。
代码如下:
#include<iostream>
#include <string.h>
using namespace std;
#define MAX 370000
int queen[MAX][10],final[9];
int Zero[MAX];
int q_queen;
int final_hash_num;
bool hash[86419760];
int step;
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
int getHashNum(int H[])//获取该状态在哈希表中的位置
{
int num=0,i;
for(i=0;i<8;i++)
{
num = num*10 + H[i];
}
return num-1234567;
}
bool SetHash(int num)
{
if(hash[num])//该排列已经搜索过
{
return false;
}else{
hash[num] = true;
return true;
}
}
bool BFS()
{
int zx,zy,nx,ny,z;
int i=0,j,hashnum;
while(i<q_queen)
{
hashnum = getHashNum(queen[i]);
if(hashnum == final_hash_num)
{
step = queen[i][9];
return true;
}
zx = Zero[i]/3; //一维的表示变化为二位的矩阵表示
zy = Zero[i]%3;
for(j=0;j<4;j++)
{
nx = zx + dx[j]; //向上、下、左、右某个方向移动
ny = zy + dy[j];
if(nx>2 || nx<0 || ny>2 || ny<0)
{
continue;
}
z = nx*3+ny;//移动后空格在一维情况下的第几个
memcpy(queen[q_queen+1], queen[i], sizeof(int)*10);
queen[q_queen+1][Zero[i]] = queen[i][z];
queen[q_queen+1][z] = 0;
if(SetHash( getHashNum(queen[q_queen+1]) ))//如果之间没有到达过这个状态
{
q_queen++;
queen[q_queen][9] = queen[i][9]+1;//记录步数
Zero[q_queen] = z;
}
}
i++;
}
return false;
}
int main()
{
int i,j;
char c;
for(i=0;i<9;i++)
{
cin >> c;
if(c == '.')
{
queen[q_queen][i] = 0;
Zero[0] = i;
}else{
queen[q_queen][i] = c - '0';
}
}
q_queen ++;
queen[q_queen][9] = 0;//表示当前搜索到第0步
for(i=0;i<9;i++)
{
cin >> c;
if(c == '.')
{
final[i] = 0;
}else{
final[i] = c - '0';
}
}
final_hash_num = getHashNum(final);
//将初始状态和末状态的排列加入哈希表,表示该情况已经搜索到
SetHash(getHashNum(queen[0]));
//广度搜索
if(BFS())
{
cout << step;
}else{
cout << -1;
}
return 0;
}