康托展开判重。也可以用打表和双向bfs做。
第一个A*搜索,A*是一种启发式搜索,g为已花代价,h为估计的剩余代价,而A*是根据f=g+h作为估价函数进行排列,也就是优先选择可能最优的节点进行扩展。可以对f进行关键字耗时600ms, 如果对h作为第一关键字, g作为第二关键字耗时170ms。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
using namespace std;
struct node
{
int a[3][3];
int c, x, y;
int f, g, h;
bool operator < (const node &F) const
{
if (h == F.h)
return g > F.g;
return h > F.h;
}
}s;
int factor[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
int dx[] = {0, 0, 1, 0, -1};
int dy[] = {0, 1, 0, -1, 0};
int f[363000];
int path[363000];
int cantor(int t[][3])
{
int x[9];
for (int i = 0; i < 9; i++)
x[i] = t[i / 3][i % 3];
int ans = 0;
for (int i = 0; i < 9; i++)
{
int cnt = 0;
for (int j = i + 1; j < 9; j++)
if (x[i] > x[j])
cnt++;
ans += cnt * factor[9 - i - 1];
}
return ans;
}
int geth(int t[][3])
{
int ans = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
if (!t[i][j]) continue;
int x = (t[i][j] - 1) / 3, y = (t[i][j] - 1) % 3;
ans += abs(x - i) + abs(y - j);
}
return ans;
}
bool judge(int t[][3])
{
int x[9];
for (int i = 0; i < 9; i++)
x[i] = t[i / 3][i % 3];
int cnt = 0;
for (int i = 0; i < 9; i++)
for (int j = i + 1; j < 9; j++)
if (x[i] > x[j] && x[i] && x[j])
cnt++;
return cnt & 1;
}
void print(int x)
{
if (s.c != x)
{
print(f[x]);
if (path[x] == 1) cout << "r";
if (path[x] == 2) cout << "d";
if (path[x] == 3) cout << "l";
if (path[x] == 4) cout << "u";
}
}
void Astar()
{
priority_queue<node> q;
bool vis[363000] = {0};
int t[][3] = {1, 2, 3, 4, 5, 6, 7, 8, 0};
int target = cantor(t);
s.c = cantor(s.a);
vis[s.c] = true;
q.push(s);
while (!q.empty())
{
node cur = q.top(); q.pop();
if (target == cur.c)
{
print(cur.c);
cout << endl;
break;
}
for (int i = 1; i <= 4; i++)
{
node c = cur; c.x += dx[i], c.y += dy[i];
if (0 <= c.x && c.x < 3 && 0 <= c.y && c.y < 3)
{
swap(c.a[c.x][c.y], c.a[cur.x][cur.y]);
c.c = cantor(c.a);
if (!vis[c.c])
{
vis[c.c] = true;
c.g++; c.h = geth(c.a); c.f = c.g + c.h;
f[c.c] = cur.c;
path[c.c] = i;
q.push(c);
}
}
}
}
}
int main()
{
ios::sync_with_stdio(0);
char ch;
while (cin >> ch)
{
if (ch == 'x')
s.x = 0, s.y = 0, s.a[0][0] = 0;
else
s.a[0][0] = ch - '0';
for (int i = 1; i < 9; i++)
{
cin >> ch;
if (ch == 'x')
s.x = i / 3, s.y = i % 3, s.a[i / 3][i % 3] = 0;
else
s.a[i / 3][i % 3] = ch - '0';
}
s.g = 0, s.h = geth(s.a), s.f = s.g + s.h;
if (judge(s.a))
cout << "unsolvable" << endl;
else
Astar();
}
return 0;
}