八数码
原题:八数码
在八数码中,估价函数就是所有数字在state中的位置与目标位置end中的位置的曼哈顿距离之和,即:
\[f(state) = \sum\limits^8_{i = 1} ( |state \_x_i - end \_x_i | + |state \_y_i - end \_y_i |)
\]
对于八数码问题有个结论:
八数码逆序对必须是偶数才有解,因为每次左右移动都不会改变逆序对的个数,只有上下移动才会增加或者减少两个逆序对,所以如果逆序对是奇数那我们无论如何都无解。
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, string> PIS;
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 bfs(string start) {
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
string end = "12345678x";
char op[] = "urdl";
priority_queue<PIS, vector<PIS>, greater<PIS>> heap;
unordered_map<string, int> dist;
unordered_map<string, pair<char, string>> prev;
heap.push({0 + f(start), start});
dist[start] = 0;
while (heap.size()) {
auto t = heap.top();
heap.pop();
string state = t.second;
if (state == end) break;
int x, y;
for (int i = 0; i < state.size(); i++) {
if (state[i] == 'x') {
x = i / 3, y = i % 3;
break;
}
}
string source = state;
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(state[x * 3 + y], state[a * 3 + b]);
if (!dist.count(state) || dist[state] > dist[source] + 1) {
dist[state] = dist[source] + 1;
prev[state] = {op[i], source};
heap.push({dist[state] + f(state), state});
}
swap(state[x * 3 + y], state[a * 3 + b]);
}
}
}
string res = "";
while (end != start) {
res += prev[end].first;
end = prev[end].second;
}
reverse(res.begin(), res.end());
return res;
}
int main() {
string start, str;
char c;
while (cin >> c) {
start += c;
if (c != 'x') str += c;
}
int cnt = 0;
for (int i = 0; i < str.size(); i++) {
for (int j = i; j < str.size(); j++) {
if (str[i] - '0' > str[j] - '0') cnt++;
}
}
if (cnt & 1) puts("unsolvable");
else {
cout << bfs(start) << endl;
}
return 0;
}