[AcWing] 845. 八数码(C++实现)---bfs的应用
1. 题目
2. 读题(需要重点注意的东西)
思路:
题意:如下九宫格玩具,问将九宫格恢复成如下状态所需的最小步数
状态怎么表示?
用一维数组来表示,如上图,就表示为 “12345678x”
如何处理状态?
① 枚举x的上下左右四个位置,交换x和该位置,然后将此状态加入队列中;
② 然后队列依次出队,出队时判断当前状态是不是最终状态"12345678x",再枚举x的上下左右四个位置,直至队列为空,则返回-1,表示不能达到最终状态。
一句话思路:
枚举x的上下左右四个位置,交换x和该位置,然后将此状态加入队列中,然后依次出队重复上述操作,在出队时判断判断当前状态是不是最终状态"12345678x"。
3. 解法
---------------------------------------------------解法---------------------------------------------------
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <queue>
using namespace std;
int bfs(string state)
{
queue<string> q; // 队列
unordered_map<string, int> d; // 哈希表:存储每个状态所用的最短步数
q.push(state);
d[state] = 0;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
string end = "12345678x"; // 定义结束状态
while (q.size())
{
auto t = q.front();
q.pop();
if (t == end) return d[t];
int distance = d[t];
// 状态转移
int k = t.find('x'); // 找x的位置,find函数会返回x的数组下标
int x = k / 3, y = k % 3; // 用x、y来对x进行二维状态表示
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]); // a * 3 + b将二维坐标又拉伸为一维
if (!d.count(t)) // 如果当前状态未出现过,加入队列中,避免重复操作
{
d[t] = distance + 1; // 步数在之前的基础上+1
q.push(t); // 将当前状态加入队列
}
swap(t[a * 3 + b], t[k]); // 交换回来,继续考虑下一个方向(上下左右)
}
}
}
return -1;
}
int main()
{
char s[2];
string state; // 存初始状态
for (int i = 0; i < 9; i ++ )
{
cin >> s;
state += *s; // 对于string而言,运算符 + 代表字符串的连接操作
}
cout << bfs(state) << endl;
return 0;
}
可能存在的问题(所有问题的位置都在上述代码中标注了出来)
4. 可能有帮助的前置习题
5. 所用到的数据结构与算法思想
- bfs
6. 总结
bfs的例题,理解思想并实现代码。