这题虽然比较难,但仍然遵循BFS的思路图片引自我的上一篇文章:
走迷宫(BFS + 队列)-CSDN博客
难点
(1)如何将一个二维数组表示的状态记录下来,并且需要便于知道某个状态是否访问过
(2)部分版本的devC++下,unordered_map 头文件没法直接 include 到文件里
解决方法
(1)将二维的数组表示成一个一维数组(一维数组和二维数组的坐标可以相互转换,具体请看代码),用 string 来存储,然后利用哈希表 unordered_map,对应每个 string 有一个 int 值,表示某个状态距离起始状态的步数;利用 unordered_map 的函数 count (s),可以计算出 s 在表中出现的次数,如果不为 0 ,则说明这种状态已经出现过。
(2)改成 #include<tr1/unordered_map>
using namespace std :: tr1;
#include<iostream>
#include<queue>
using namespace std;
#include<tr1/unordered_map>
using namespace std::tr1;
queue<string> q;
unordered_map<string, int> dist;
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
int bfs(string s)
{
string end = "12345678x"; // 终止条件
q.push(s); // 队列初始化
dist[s] = 0;
while(!q.empty())
{
string now = q.front();
int step = dist[now];
if(now == end) return step;
int k = now.find('x');
// 由一维数组的坐标得到二维数组的坐标 x,y
int x = k / 3;
int 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)
{
// 由二维数组的坐标得到一维数组的坐标 k2
int k2 = 3 * a + b;
// swap还能用于string里两个字母的交换
swap(now[k], now[k2]);
if(!dist.count(now))
{
dist[now] = step + 1;
q.push(now);
}
// 记得将字符串复原,防止dist误认为没有访问过
swap(now[k], now[k2]);
}
}
q.pop(); // 四种情况走完,弹出队首
}
return -1;
}
int main()
{
string s;
for(int i=0;i<9;++i)
{
char c;
cin>>c;
s += c;
}
cout<<bfs(s);
return 0;
}