问题描述:在九宫格中放置8个数,有一个为空格。给定初始状态九宫格,和目标状态九宫格,问需要多少步可以将初始状态变成目标状态。如果无法达到输出-1,如果可以达到,输出最少的步骤数。
问题分析:本题属于搜索算法中的经典题目。可以用很多方法来解答,一般有A*算法和广度搜索BFS。因为广度搜索较容易理解,所以这里就用BFS来解答。
已知一个初始状态,如何利用BFS,搜索到最终状态?
如下图所示,每一次画出当前可移动之后的状态,每次移动一个方块,层数表示移动的步骤数,一旦搜索到目标状态,就停止搜索返回层数,即最少的步骤数。
这里有几个问题需要注意:
1.如何进行重复性判断? 一旦搜索到重复的状态图,表示前面已经搜索到过了,所以重复的就不需要考虑了。我是通过set集合,将每个图映射成一个整数,将其压入set集合中,当下次来一个新的整数,只要判断它是否在set集合中即可。
2.如何存储图的状态?用一个结构体node,里面保存一个char[3][3]数组和空格的位置。
3.如何表示空格周围方块的移动?其实只要更新空格的位置,再将空格位置上的原值移动到原来空格的位置即可。简而言之,就是交换两个数值的位置,只不过这里有一个值是’.’
4.另外注意,移动之后数码块的合法性检查,即是否超出了边界。
代码展示:
#include <iostream>
#include <queue>
#include <string>
#include <set>
using namespace std;
#define N 10005;
char mp[3][3],gp[3][3];
int dir[4][2] = {0,1,1,0,-1,0,0,-1}; //表示上下左右四个方向
struct node{ //结点代表一种状态
int x,y;
int step;
char cur_mp[3][3]; //当前图案
node(int x,int y,int step){
this->x = x;
this->y = y;
this->step = step;
}
};
set<int> st;
queue<node> q;
bool check(node cur){ //判断是否达到终态
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(cur.cur_mp[i][j]!=gp[i][j])
return false;
}
}
return true;
}
int cal(node cur){ //将每种状态映射到一个整数
int result = 0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(cur.cur_mp[i][j]!='.')
result = result*10+(cur.cur_mp[i][j]-'0');
else
result = result*10+9;
}
}
return result;
}
void bfs(){
st.clear();
if(!q.empty())
st.insert(cal(q.front()));
while(!q.empty()){
node cur = q.front();
q.pop();
if(check(cur)){ //检查是否到了终态
cout<<cur.step<<endl;
return;
}
//改动空格周围的四个数码块
for(int i=0;i<4;i++){
int xx = cur.x + dir[i][1];
int yy = cur.y + dir[i][0];
if(xx<0 || xx>2 || yy<0 || yy>2)
continue; //边界检查
node nt = node(xx,yy,cur.step+1);
memcpy(nt.cur_mp,cur.cur_mp,sizeof(cur.cur_mp));
int temp = nt.cur_mp[xx][yy];
nt.cur_mp[xx][yy] = '.';
nt.cur_mp[cur.x][cur.y] = temp;
int val = cal(nt);
if(st.find(val) != st.end()) //去掉重复的图
continue;
st.insert(val);
q.push(nt);
}
}
cout<<-1<<endl;
}
int main(){
string str1,str2;
cin>>str1>>str2;
int bx=0,by=0;
while(!q.empty())
q.pop();
int len = 0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
mp[i][j] = str1[len++];
if(mp[i][j]=='.'){
bx = i;
by = j;
}
}
}
node cur = node(bx,by,0);
memcpy(cur.cur_mp,mp,sizeof(mp));
q.push(cur);
len = 0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
gp[i][j] = str2[len++];
}
}
bfs();
return 0;
}