题目
题目链接
如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
思路:
本题直接在棋盘上动手不是很好,要将每个棋盘的状态用矩阵压缩变成字符串进行bfs比较好,使用map方便进行判断是否走到过这种局势,queue更是bfs不能缺少的。
#include <iostream>
#include <string>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;
string first, last, str1, str2; //这里选择string类作为输出
int flag, x, y;
map<string, int>dis, vis; //用map去重同时方便查询,dis表示开始找的点到当前点的距离
queue<string>q1, q2; //两个队列
char m[3][3]; //九宫字符数组
const int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
bool in(int x, int y){ //判断是否超出九宫
return x >= 0 && x < 3 && y >= 0 && y < 3;
}
void toMatrix(string str){ //把字符串变成九宫字符数组
for(int i = 0; i < str.size(); i++){ //算法实现比较简单,模拟一下即可
m[i / 3][i % 3] = str[i];
}
}
string toString(){ //把九宫字符数组转化为字符串
string str;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
str.push_back(m[i][j]); //一个一个push_back
}
}
return str;
}
int dbfs(){ //重头戏来了
q1.push(first); //q1从起点开始找
dis[first] = 1; //一开始赋值1
vis[first] = 1; //q1访问过的赋值为1
q2.push(last); //q2从终点开始找
dis[last] = 1;
vis[last] = 2; //q2访问过的赋值为2
while(!q1.empty() && !q2.empty()){//如果其中一个队列为空,还没有找到解,说明无解
if(q1.size() < q2.size()){ //根据队列的容量来判断是从哪一端找,谁少谁出列
str1 = q1.front();
q1.pop();
flag = 1; //作一下是哪一个队列出列的标记
}
else{
str1 = q2.front();
q2.pop();
flag = 2;
}
toMatrix(str1); //转化为九宫数组
for(int i = 0; i < 3; i++){ //找小数点
for(int j = 0; j < 3; j++){
if(m[i][j] == '.'){
x = i;
y = j;
}
}
}
for(int i = 0; i < 4; i++){ //四个方向开始试探
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(in(tx, ty)){
swap(m[x][y], m[tx][ty]); //试探
str2 = toString();
if(!dis.count(str2)){ //如果没有访问,就一下标记
dis[str2] = dis[str1] + 1;
vis[str2] = vis[str1]; //这样写可以避免判断是哪一端找的str2
if(flag == 1){ //谁出的列谁就入队
q1.push(str2);
}else if(flag == 2){
q2.push(str2);
}
}
else{ //如果已经访问判断标记是否重合
if(vis[str1] + vis[str2] == 3){
int ans = dis[str1] + dis[str2] - 1;//这里记得减一
return ans;
}
}
swap(m[x][y], m[tx][ty]); //试探完毕一定要记得要回溯
}
}
}
return -1; //没有找到,返回-1
}
int main(){
cin >> first >> last;
if(first == last){
cout << 0 << endl;
}
else{
cout << dbfs() << endl;
}
return 0;
}