❤作者:那些年丶我们逃过的课
❤博客主页:那些年丶我们逃过的课的博客_CSDN博客-c++题目,c++学习记录,c++小游戏领域博主
❤码云gitee:我的码云 - Gitee.com
❤期待你的关注,如果觉得还可以的话,可以点赞评论支持一下,每个评论我都会回访的🎉
八数码难题
题目描述
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
输入格式
输入初始状态,一行九个数字,空格用0表示
输出格式
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
样例 #1
样例输入 #1
283104765
样例输出 #1
4
使用 BFS搜索,每当搜索到一个新的状态时,就将这个新的状态放入队列内
然后存储 0 的位置,以便于以后的搜索
优化:
用一维储存,比二维储存更加方便
那么就要在每次交换时,把一维转换为二维,交换位置后再转为一维储存
就能达到优化的效果了
#include<bits/stdc++.h>
using namespace std;
map<int,bool> mp; //建立映射
int ed=123804765;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0}; //状态偏移量
queue< pair <int,int> >q; //队列 first表示状态 second表示步数
int move(int st,int t){
int temp[4][4],zx,zy;
for(int i=3;i>=1;i--){
for(int j=3;j>=1;j--){
temp[i][j]=st%10;
if(temp[i][j]==0) zx=i,zy=j;
st/=10;
}
}
int nx=zx+dx[t];
int ny=zy+dy[t];
if(!(nx>=1&&nx<=3&&ny>=1&&ny<=3)){
return 0; //判断0移动后的位置是否合法
}
swap(temp[nx][ny],temp[zx][zy]); //交换位置
int res=0;
for(int i=1;i<=3;i++){
for(int j=1;j<=3;j++){
res=res*10+temp[i][j];
}
}
return res;
}
void bfs(int bg){
q.push(make_pair(bg,0));
mp[bg]=1;
while(!q.empty()){
int hx=q.front().first; //取出队头的状态
int hs=q.front().second; //取出到达该状态的步数
q.pop(); //队头元素出队
for(int i=0;i<4;i++){
int nx=move(hx,i); //获得了新的状态
int ns=hs+1;
if(nx&&mp[nx]==0){ //验证状态合法性
mp[nx]=1;
if(nx==ed){
cout<<ns;
return; //判断是否达到目标状态
}
q.push(make_pair(nx,ns)); //新状态入队
}
}
}
cout<<0; //考虑目标状态与初始状态相同的情况
return;
}
int main(){
int bg;
cin>>bg;
bfs(bg);
return 0;
}