康复计划之搜索 1
因为有个小学弟在第二天就说ida * 看不懂,搞得我挺慌 我可以说我也不是很熟么
题意:
经典八数码
思路:
这里提供的是单向bfs + 打表思路,本来想复习ida * 但是不小心看到了kuangbin的思路,就写了一下。
简单说就是我从起始状态 123456780 开始对0进行bfs,通过康托展开的hash函数进行记录状态和路径。询问时对哈希值进行询问和查找。
实际上并没有用到康托展开的性质,只是通过2进制hash而已……
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <string>
using namespace std;
const int maxn = 400000;
int fac[] = { 0, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };
string path[maxn];
bool vis[maxn];
int dx[] = { 0, -1, 0, 1 };
int dy[] = { -1, 0, 1, 0 };
char dir[] = "rdlu";
struct node {
int s[9];
int zero_pos;
int hash;
string path;
};
int cantor_hash(int s[])
{
int res = 0;
for (int i = 0; i < 9; i++) {
int renum = 0;
for (int j = i + 1; j < 9; j++)
if (s[i] > s[j])
renum++;
res += (renum * fac[9 - i - 1]);
}
return res;
}
void init()
{
memset(vis, false, sizeof vis);
node cur, nxt;
for (int i = 0; i < 8; i++)
cur.s[i] = i + 1;
cur.s[8] = 0;
cur.zero_pos = 8;
cur.hash = cantor_hash(cur.s);
path[cur.hash] = "";
vis[cur.hash] = true;
queue<node> que;
que.push(cur);
while (!que.empty()) {
cur = que.front();
que.pop();
int x = cur.zero_pos / 3;
int y = cur.zero_pos % 3;
for (int i = 0; i < 4; i++) {
int xx = x + dx[i];
int yy = y + dy[i];
if (xx < 0 || xx > 2 || yy < 0 || yy > 2)
continue;
nxt = cur;
nxt.zero_pos = xx * 3 + yy;
nxt.s[cur.zero_pos] = nxt.s[nxt.zero_pos];
nxt.s[nxt.zero_pos] = 0;
nxt.hash = cantor_hash(nxt.s);
if (!vis[nxt.hash]) {
nxt.path = dir[i] + cur.path;
path[nxt.hash] = nxt.path;
que.push(nxt);
vis[nxt.hash] = true;
}
}
}
}
int main()
{
init();
node cur;
char buf[2];
while (scanf("%s", buf) != EOF) {
if (buf[0] == 'x') {
cur.zero_pos = 0;
cur.s[0] = 0;
} else
cur.s[0] = buf[0] - '0';
for (int i = 1; i < 9; i++) {
scanf("%s", buf);
if (buf[0] == 'x') {
cur.zero_pos = i;
cur.s[i] = 0;
} else
cur.s[i] = buf[0] - '0';
}
cur.hash = cantor_hash(cur.s);
//cout << cur.hash << endl;
if (vis[cur.hash])
cout << path[cur.hash] << endl;
else
puts("unsolvable");
}
return 0;
}