题目链接:1077 -- Eight Problem - 1043
两个题目几乎完全一致。不同的是,HDU的八数码这道题需要一次bfs,起点为123456789X,遍历完所有状态,同时用pre数组记录上一个状态,然后每次输入只需要一个while进行O(1)的查询。
方法没有什么特殊的,我用的是普通的bfs。这道题和其他的搜索题目不一样的一点是,9个格子,太大没有办法标记。这时可以利用康托展开。
康托展开是一个完美hash函数,可以将n个数的所有排列组合状态进行压缩。9个数进行全排列,记录状态需要大小1e10的数组,经过康托展开的映射后只需要大小为9!的数组。一个数组经过这个过程,可以得到这个数组在全排列的序号。比如213是组合{1, 2, 3}中的第2小的组合(下标从0开始)。那么该如何得到213的康托展开就由1*2!+0*1!+0*0!得到。第一位是2,当第一位的数小于2时,排列数一定小于213,比如123、132,所以有1*2!,再看小于第二位1的,小于2的数没有 所以有0*1!=0,所以小于213的{1,2,3}排列数有1*2!+0*1!=2个,所以213是第3个大的数。
POJ 1077
#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
#define FIN freopen("in.txt", "r", stdin);
#define FOUT freopen("out.txt", "w", stdout);
const int INF = 0x3f3f3f3f;
const int MAXN = 400005;
char op[MAXN];
int pre[MAXN], fac[55];
bool vis[MAXN], flag;
int CantorExpansion(LL m)
{
int str[10], pos = 8;
while (m)
{
str[pos--] = m % 10;
m /= 10;
}
int ret = 0;
for (int i = 0; i < 8; i++)
{
int tmp = 0;
for (int j = i + 1; j < 9; j++)
if (str[i] > str[j])
tmp++;
ret += tmp * fac[8 - i];
}
return ret;
}
void bfs(LL start)
{
memset(vis, false, sizeof(vis));
memset(op, -1, sizeof(op));
queue<LL> q;
int id;
q.push(start);
id = CantorExpansion(start);
vis[id] = true;
while (!q.empty())
{
LL cur = q.front();
q.pop();
if (cur == 123456789)
{
stack<char> sta;
id = CantorExpansion(cur);
while (op[id] != -1)
{
sta.push(op[id]);
id = pre[id];
}
while (!sta.empty())
{
printf("%c", sta.top());
sta.pop();
}
puts("");
flag = true;
return;
}
int str[10], pos = 8, nine;
LL tcur = cur;
while (tcur)
{
if (tcur % 10 == 9)
nine = pos;
str[pos--] = tcur % 10;
tcur /= 10;
}
for (int i = 0; i < 4; i++)
{
if ((i == 0 && nine / 3 == 0) || (i == 1 && nine / 3 == 2) || (i == 2 && nine % 3 == 0) || (i == 3 && nine % 3 == 2))
continue;
int tstr[10];
memcpy(tstr, str, 9 * sizeof(int));
if (i == 0)
swap(tstr[nine], tstr[nine - 3]);
else if (i == 1)
swap(tstr[nine], tstr[nine + 3]);
else if (i == 2)
swap(tstr[nine], tstr[nine - 1]);
else if (i == 3)
swap(tstr[nine], tstr[nine + 1]);
LL tt = 0;
for (int i = 0; i < 9; i++)
tt = tt * 10 + tstr[i];
int id = CantorExpansion(tt);
if (!vis[id])
{
if (i == 0)
op[id] = 'u';
else if (i == 1)
op[id] = 'd';
else if (i == 2)
op[id] = 'l';
else if (i == 3)
op[id] = 'r';
pre[id] = CantorExpansion(cur);
vis[id] = true;
q.push(tt);
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
FIN;
#endif // ONLINE_JUDGE
//bfs();
fac[0] = fac[1] = 1;
for (int i = 2; i < 9; i++)
fac[i] = fac[i - 1] * i;
char str[50];
while (gets(str))
{
flag = false;
int s = 0;
for (int i = 0; str[i]; i++)
{
if (str[i] == 'x')
s = s * 10 + 9;
else if (str[i] != ' ')
s = s * 10 + str[i] - '0';
}
int id = CantorExpansion(s);
if (id == 0)
{
printf("lr\n");
continue;
}
bfs(s);
if (!flag)
printf("unsolvable\n");
}
return 0;
}
HDU 1043
#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
#define FIN freopen("in.txt", "r", stdin);
#define FOUT freopen("out.txt", "w", stdout);
const int INF = 0x3f3f3f3f;
const int MAXN = 400005;
char op[MAXN];
int pre[MAXN], fac[55];
bool vis[MAXN];
int CantorExpansion(LL m)
{
int str[10], pos = 8;
while (m)
{
str[pos--] = m % 10;
m /= 10;
}
int ret = 0;
for (int i = 0; i < 8; i++)
{
int tmp = 0;
for (int j = i + 1; j < 9; j++)
if (str[i] > str[j])
tmp++;
ret += tmp * fac[8 - i];
}
return ret;
}
void bfs()
{
fac[0] = fac[1] = 1;
for (int i = 2; i < 9; i++)
fac[i] = fac[i - 1] * i;
memset(vis, false, sizeof(vis));
memset(op, -1, sizeof(op));
queue<LL> q;
int id;
q.push(123456789);
id = CantorExpansion(123456789);
vis[id] = true;
while (!q.empty())
{
LL cur = q.front();
q.pop();
int str[10], pos = 8, nine;
LL tcur = cur;
while (tcur)
{
if (tcur % 10 == 9)
nine = pos;
str[pos--] = tcur % 10;
tcur /= 10;
}
for (int i = 0; i < 4; i++)
{
if ((i == 0 && nine / 3 == 0) || (i == 1 && nine / 3 == 2) || (i == 2 && nine % 3 == 0) || (i == 3 && nine % 3 == 2))
continue;
int tstr[10];
memcpy(tstr, str, 9 * sizeof(int));
if (i == 0)
swap(tstr[nine], tstr[nine - 3]);
else if (i == 1)
swap(tstr[nine], tstr[nine + 3]);
else if (i == 2)
swap(tstr[nine], tstr[nine - 1]);
else if (i == 3)
swap(tstr[nine], tstr[nine + 1]);
LL tt = 0;
for (int i = 0; i < 9; i++)
tt = tt * 10 + tstr[i];
int id = CantorExpansion(tt);
if (!vis[id])
{
if (i == 0)
op[id] = 'd';
else if (i == 1)
op[id] = 'u';
else if (i == 2)
op[id] = 'r';
else if (i == 3)
op[id] = 'l';
pre[id] = CantorExpansion(cur);
vis[id] = true;
q.push(tt);
}
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
FIN;
#endif // ONLINE_JUDGE
bfs();
char str[50];
while (gets(str))
{
int s = 0;
for (int i = 0; str[i]; i++)
{
if (str[i] == 'x')
s = s * 10 + 9;
else if (str[i] != ' ')
s = s * 10 + str[i] - '0';
}
int id = CantorExpansion(s);
if (id == 0)
{
printf("lr\n");
continue;
}
if (op[id] == -1)
{
printf("unsolvable\n");
continue;
}
while (id != 0)
{
printf("%c", op[id]);
id = pre[id];
}
puts("");
}
return 0;
}