AcWing 845. 八数码-个人理解与细节注释
原题链接
中等
作者:
现代修士o_O
,
2021-04-28 16:00:46
,
所有人可见
,
阅读 164
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <queue>
using namespace std;
int bfs(string start)
{
string end = "12345678x";
queue<string> q;//每个状态用字符串来存储表示
unordered_map<string, int> d;//每个状态与初始状态的距离
q.push(start);//把初始状态放入队列
d[start] = 0;//它与自己相差0的距离
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
while (q.size())
{
auto t = q.front();//取出队头状态
q.pop(); //出队
//下面出队的时候进行特别的判断!!
int distance = d[t]; //它距离初始状态的距离, 需要记录下来,下面的d[t] 需要用到
if(t == end) return distance; // 如果t已经是终点的状态,直接输出答案!它们之间的距离
//出队判断结束
//下面是t状态的转移
int k = t.find('x'); // 找出x在t中出现的第一个位置,等等这不就是kmp吗!用stl确实可以做kmp那题,不过最后一组数据TLE了
int x = k / 3, y = k % 3; // 一维位置k转二维位置(x,y),前提条件一维二维都要从下标0开始咯
for (int i = 0; i < 4; i ++ )//遍历四个方向
{
int a = x + dx[i], b = y + dy[i];//得到一个方向上的坐标
if (0 <= a && a < 3 && 0 <= b && b < 3)//若坐标合法
{
swap(t[k], t[a * 3 + b]); // a * 3 + b 二维位置(a, b)转换为一维位置a * 3 + b
//判断一下,转换后的状态有没有出现过,也就是看t有没有在d中出现过
if (!d.count(t))//使用count,返回的是被查找元素的个数。如果有,返回1;否则,返回0。注意,map中不存在相同元素,所以返回值只能是1或0。
{
d[t] = distance + 1; //在原有的状态上加1
q.push(t);
}
swap(t[k], t[a * 3 + b]);//恢复现场,进行下一次方向的判断
//担心会反复进入同一个状态? d记录了遍历过的状态
}
}
}
return -1; //若有转换成终点状态,在出队那时就输出了,如果没输出,那就意味着失败了
}
int main()
{
string start;
for (int i = 0; i < 9; i ++ )
{
char c;
cin >> c;
start += c;
}
cout << bfs(start) << endl;
return 0;
}