You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
2.6 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
typedef unordered_map<string, int> MSI;
typedef unordered_map<string, pair<char, string>> MSP;
string st, ed = "12345678x";
//上下左右
char op[] = {'u', 'd', 'l', 'r'};
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
//前驱
MSP pre;
//伟大的结构体放光芒
struct Node {
int dist;
string str;
bool operator<(const Node &t) const {
return dist > t.dist; //距离大的反而小,距离小的反而大。所以,配合优先队列(大顶堆),小的在上,大的在下
}
};
//估值函数,用曼哈顿距离估值
int f(string str) {
int res = 0;
for (int i = 0; i < str.size(); i++)
if (str[i] != 'x') {
int t = str[i] - '1';
res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);
}
return res;
}
string astar() {
MSI dist;
priority_queue<Node> q;
//将估价函数与字符串形成数对,放入到优先队列中
q.push({f(st), st});
dist[st] = 0; //记录距离为0
while (q.size()) {
string t = q.top().str;
q.pop();
if (t == ed) break;
int k = t.find('x');
int tx = k / 3, ty = k % 3;
for (int i = 0; i < 4; i++) {
int x = tx + dx[i], y = ty + dy[i];
if (x < 0 || x >= 3 || y < 0 || y >= 3) continue; //出界
string v = t; //将t字符串复制出来一个生成 v字符串
swap(v[k], v[x * 3 + y]); //将原字符串中x与目标位置进行交换生成新的目标状态字符串v
if (dist[v]) continue;
dist[v] = dist[t] + 1; // 更新最小值
q.push({dist[v] + f(v), v}); // 将新的估价函数计算更新,重新入队列
pre[v] = {op[i], t};
}
}
//将路径倒转过来
string res;
while (ed != st) {
res += pre[ed].first;
ed = pre[ed].second;
}
reverse(res.begin(), res.end());
return res;
}
int main() {
char c;
for (int i = 0; i < 9; i++) cin >> c, st += c;
//八数码定理
int nums = 0;
for (int i = 0; i < 9; i++) {
if (st[i] == 'x') continue;
for (int j = i + 1; j < 9; j++) {
if (st[j] == 'x') continue;
if (st[j] < st[i]) nums++; //逆序数
}
}
//奇数个逆序对,无解
if (nums & 1)
puts("unsolvable");
else //运行astar算法返回最短距离
cout << astar() << endl;
return 0;
}