一.引入:
二.分析:
由题意可知该棋盘大小仅仅为3*3,而且需要我们求最短路,因此我们可以尝试利用字符串来存当前或者最终状态,其次我们可以利用stl里面的unordered_map来存每个字符串的哈希值,防止状态重复,最后,当哈希值与最终状态的哈希值相同时,即为成功移动。
对于非图论的类迷宫型最短路,我比较倾向于利用搜索来解决问题,这次我决定利用bfs来解决问题。
三:bfs原理分析:
首先,bfs主要是将每一层的情况都遍历一遍之后才会进入到下一层,下面我用一个草图来简单分析bfs的基本原理:
像这样一个矩阵,从左上角走到右下角,每次只能走在‘0’上,用bfs则是这样走的(注:红色数字代表第几布)
说明:第一步有两种情况:向右或者向下走一步,之后1走到2可以有3种情况:向右或者向下,如果重复了,那么就不用走了,以此类推,第9步一个是在右上角,一个是在右下角,刚好符合在右下角的情况,因此步数为9。
四:实现
我们可以将8数码问题抽象成一个迷宫问题,每次交换一次,抽象成走一步,直到交换到目标状态为止,下面是代码的实现:
#include<bits/stdc++.h>
using namespace std;
int bfs(string a)
{
unordered_map<string,int>d;//stl的哈希
queue<string>q;//定义一个队列,防止重复的状态再次进入交换操作
q.push(a);
d[a]=0;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};//上下左右的操作前提
string end={"123804765"};//定义目标状态
while(q.size())
{
auto t=q.front();
q.pop();
if(t==end)return d[t];
int distance=d[t];
int k=t.find('0');//每次是将0交换,因此需要找到0的位置
int x=k/3,y=k%3;//一维数组抽象成二维数组,行除3,列模3,这里是找到0在二维数组里的位置
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[a*3+b],t[k]);
if(!d.count(t))
{
d[t]=distance+1;//记录当前步数
q.push(t);
}
swap(t[a*3+b],t[k]);//恢复之前的状态
}
}
}
return -1;
}
int main()
{
string a;
cin>>a;
cout<<bfs(a)<<endl;
return 0;
}
五:总结:
这就是bfs用图来描述,大概就是将每一层的情况遍历一般,判断是否存在某一个点是符合操作的,如果存在,那么就输出当前层数。