题目:http://acm.hdu.edu.cn/showproblem.php?pid=1043
八数码问题,给出一个3x3的棋盘,上有1~8 共8个棋子,x表示空格,问是否能将棋子顺序还原为12345678x
棋盘中只包含数字1~8和x,把x记为0,最终要还原成123456780,输入的棋盘可看成是 0 ~ 8 这9个数的全排列 中的一种排列,要判断输入的棋盘是否可以还原成123456780,现可以反向解答,以123456780为初始状态,0向4个方向走,看是否会出现输入的状态,若能,则可以还原,否则不可还原。
运用康托展开:康托展开满足双射的关系,可以根据当前的排列求出它是全排列中的第几个
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
#include<sstream>
#include<cstdio>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 362880 + 7; // 876543210 的hash值为362880,即最大只会达到362880
static const int FAC[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; // 阶乘
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
char op[] = "udlr"; // 因为是反向bfs,所以这里与dir的方向是相反的。
int result = 46234; // 123456780 的hash值为46234,
int tmp[9]; // 把3x3的图存成1维的
int vis[MAXN];
string path[MAXN];
// 康托展开
int cantor(int *a) // 计算数值排行第几
{
int x = 0;
for(int i = 0; i < 9; i++)
{
int smaller = 0;
for(int j = i + 1; j < 9; j++)
{
if(a[j] < a[i])
smaller++;
}
x += smaller * FAC[9 - i - 1];
}
return x + 1;
}
// 逆康托展开
void decantor(int x, int *a) // 由排行第几计算数值是多少
{
vector<int> v;
for(int i = 0; i < 9; i++)
v.push_back(i);
for(int i = 0; i < 9; i++)
{
int r = x % FAC[9 - i - 1];
int t = x / FAC[9 - i - 1];
x = r;
sort(v.begin(), v.end());
a[i] = v[t];
v.erase(v.begin() + t);
}
}
struct node
{
string path;
int hashs;
int pos;
}now, nxt;
void bfs()
{
queue<node> q;
memset(vis, 0, sizeof(vis));
for(int i = 0; i < 8; i++) // (最终目标是123456780)tmp初始为123456780,从这里开始反向bfs
tmp[i] = i + 1;
tmp[8] = 0;
now.path = "";
now.hashs = result;
now.pos = 8;
path[result] = "";
vis[result] = 1;
q.push(now);
while(!q.empty())
{
now = q.front(); q.pop();
for(int i = 0; i < 4; i++)
{
int tx = now.pos / 3 + dir[i][0];
int ty = now.pos % 3 + dir[i][1];
if(tx >= 0 && tx < 3 && ty >= 0 && ty < 3)
{
nxt = now;
nxt.pos = tx * 3 + ty;
decantor(now.hashs - 1, tmp); // 求上一步的tmp
swap(tmp[now.pos], tmp[nxt.pos]); // 移动x的位置
nxt.hashs = cantor(tmp); // 得到新的tmp
if(!vis[nxt.hashs])
{
vis[nxt.hashs] = 1;
nxt.path = op[i] + nxt.path;
q.push(nxt);
path[nxt.hashs] = nxt.path;
}
}
}
}
}
int main()
{
bfs();
string str;
while(getline(cin, str))
{
stringstream s(str);
char x;
int tt = 0;
while(s >> x)
{
if(x == 'x')
tmp[tt++] = 0;
else
tmp[tt++] = x - '0';
}
int hashs = cantor(tmp);
if(!vis[hashs])
cout << "unsolvable" << endl;
else
cout << path[hashs] << endl;
}
return 0;
}