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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}