分析:
x每移动一次就对应一个状态,这个状态,对应的就是二维图平面中的一个点。然后,题目又提到了最短,那么显然,可以采用BFS(最简单的办法,当然A*更好)。
解答(BFS)
#include <iostream>
#include <queue>
#include <unordered_map>
#include <string>
using namespace std;
int main() {
string des = "12345678x"; // 目标状态
string start; // 起始状态
int dx[] = {-1, 0, 1, 0}; // 顺时针旋转
int dy[] = {0, 1, 0, -1};
for (int i = 0; i < 9; i++) { // 输入字符串
char c;
cin >> c;
start += c;
}
queue<string> q; // 实现BFS的队列
q.push(start); // 其实状态入队
unordered_map<string, int> mp; // 存储到达某个状态的最短步数
mp[start] = 0; // 起点的步数为 0
while (!q.empty()) {
string s = q.front(); // 队首元素
q.pop(); // 将其弹出
int dis = mp[s]; // 此状态的”步数”
if (s == des) { // 是否已经到达终点
cout << dis;
return 0;
}
int idx = s.find('x'); // 找到’x’对应下标
int x = idx / 3; // 对应‘x’的 x坐标
int y = idx % 3; // 对应‘x’的 y坐标
for (int i = 0; i < 4; i++) {
int next_x = x + dx[i];
int next_y = y + dy[i];
swap(s[idx], s[next_x * 3 + next_y]); // 得到下一个“状态”
if (next_x < 0 || next_x > 2 || next_y < 0 || next_y > 2 ) {
// 越界 或者 已经有最短路径了
continue;
}
if (!mp.count(s)) { // 如果是第一次到达这个状态, 即最短步数
mp[s] = dis + 1; // 记录到达这个状态的最短步数
q.push(s); // 此状态 入队
}
swap(s[idx], s[next_x * 3 + next_y]); // 还原
}
}
cout << -1; // 没找到结果
return 0;
}
解答(A*):
这个时候,就要祭出我们的A*,就是用小顶堆(priority_queue),每次从中选一个最可能的状态———一个确定当前状态到目标状态距离,以及已经走过步数,的评估函数。
不要用这个办法,会超时,可能是priority_queue的排序消耗的时间比算法优化的时间更多,最后会超时。