本文已参与[新人创作礼]活动,一起开启掘金创作之路。
题目描述
845. 八数码 - AcWing题库
在一个 3×3 的网格中,1∼8 这 8 个数字和一个 x 恰好不重不漏地分布在这 3×3 的网格中。
例如:
1 2 3
x 4 6
7 5 8
在游戏过程中,可以把 x 与其上、下、左、右四个方向之一的数字交换(如果存在)。
我们的目的是通过交换,使得网格变为如下排列(称为正确排列):
1 2 3
4 5 6
7 8 x
例如,示例中图形就可以通过让 x 先后与右、下、右三个方向的数字交换成功得到正确排列。
交换过程如下:
1 2 3 1 2 3 1 2 3 1 2 3
x 4 6 4 x 6 4 5 6 4 5 6
7 5 8 7 5 8 7 x 8 7 8 x
现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。
输入格式
输入占一行,将 3×3 的初始网格描绘出来。
例如,如果初始网格如下所示:
1 2 3
x 4 6
7 5 8
则输入为:1 2 3 x 4 6 7 5 8
输出格式
输出占一行,包含一个整数,表示最少交换次数。
如果不存在解决方案,则输出 −1−1。
输入样例:
2 3 4 1 5 x 7 6 8
输出样例
19
问题解析
每次在矩阵中找到x的位置,把它和上下左右四个位置的数都交换一下(4种情况)比如题目所给的情况,第一次交换后就变成:
x 2 3 1 2 3 1 2 3
1 4 6 4 x 6 7 4 6
7 5 8 7 5 8 x 5 8
还有一种情况因为越界了所以不考虑,给最初的矩阵赋一个权值0,之后每有一次操作,权值都+1,判断当矩阵变为要求的情况时,返回当前的权值,这个权值就是最少的步数。如果列举所有情况任然没有要求的那种,就返回-1。
AC代码
#include<iostream>
using namespace std;
#include<unordered_map>
#include<queue>
#include<algorithm>
int bfs(string str)
{
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
unordered_map<string,int>mymap;
queue<string>que;
que.push(str);
string end="12345678x";
mymap[str]=0;
while(que.size())
{
string t=que.front();
int ans=mymap[t];
if(t==end)return ans;
que.pop();
int k=t.find('x');
int x=k/3,y=k%3;
for(int i=0;i<4;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a>=0&&a<3&&b>=0&&b<3)
{
swap(t[k],t[a*3+b]);
if(!mymap.count(t))
{
mymap[t]=ans+1;
que.push(t);
}
swap(t[k],t[a*3+b]);
}
}
}
return -1;
}
int main()
{
string str;
char c;
for(int i=0;i<9;i++)
{
cin>>c;
str+=c;
}
cout<<bfs(str)<<endl;
return 0;
}