这个游戏小时候玩过,在书上看到这个题后,又想起来HDU 有一个关于这个的题。
八数码是二维的表示形式,我们也可以把它的表示形式压缩为一维的。
这样就可以存在set或map里了,或者是把每个八数码的排列Hash一下也可以。
然后就从每个状态开始搜四个方向看0是否能够移动。
书上的这个实现还是比较容易的。直接开一个len数组,每次搜到的状态的len值为之前状态的len+1即可。
但是HDU 1043,用最暴利的方式肯定是超时的。
还有HDU 1043,有个Trick,如果输入的是"12345678x",只输出换行,否则是Wrong Answer的。题目也没说~~
那我们是不是可以预处理呢? 让开始的状态为"12345678x",往回搜其他的状态把路径存在结构体里。
在结构体里定义两个int变量:front,arr分别表示 当前状态的前驱 和 当前状态的下标。
并用map存每个状态在结构体中的下标位置。我们就可以找到搜索的路径了~
写的比较水,见谅~
附上代码:
#include <stdio.h>
#include <string.h>
#include <queue>
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <map>
using namespace std;
map<string,int> mm;
char end[10];
int dir[4][2] = {-1,0, 0,-1, 0,1, 1,0}; //上,左,右,下
char cc[6] ="ulrd";
struct ak
{
char ch[10];
int x, y; //空格所在坐标
int front; //前驱下标
int arr; //当前下标
int where; //方向
}temp, temp2, gg[400000];
queue<ak> qq;
void gao(int x)
{
if(x == 0)
{
return ;
}
printf("%c", cc[gg[x].where]);
gao(gg[x].front);
}
void bfs()
{
int cnt = 0;
while(!qq.empty())
{
temp = qq.front();
qq.pop();
for(int i = 0; i < 4; i++)
{
temp2 = temp;
temp2.x = temp.x + dir[i][0];
temp2.y = temp.y + dir[i][1];
if(temp2.x >= 0 && temp2.x < 3 && temp2.y >= 0 && temp2.y < 3)
{
swap(temp2.ch[temp2.x*3+temp2.y], temp2.ch[temp.x*3+temp.y]);
if(mm.find(temp2.ch) == mm.end())
{
gg[++cnt].where = 3-i; //为什么是3-i? 因为是倒着推,所以方向相反
gg[cnt].x = temp2.x; //存当前状态的空格所在坐标
gg[cnt].y = temp2.y; //存当前状态的空格所在坐标
strcpy(gg[cnt].ch,temp2.ch);
gg[cnt].front = temp.arr; //存结构体的前驱下标
gg[cnt].arr = cnt; //存结构体的当前下标
qq.push(gg[cnt]);
mm[temp2.ch] = cnt;
}
}
}
}
}
int main()
{
char tempch[1000];
int len;
mm["12345678x"] = 0;
strcpy(gg[0].ch, "12345678x");
gg[0].arr = 0;
gg[0].x = gg[0].y = 2;
qq.push(gg[0]);
bfs();
while(gets(tempch))
{
int len = strlen(tempch);
int con = 0;
for(int i = 0; i < len; i++)
{
if((tempch[i] >= '0' && tempch[i] <= '9') || tempch[i] == 'x')
{
end[con++] = tempch[i];
}
}
end[con] = '\0';
if(mm.find(end) != mm.end())
{
gao(mm[end]);
}
else
{
printf("unsolvable");
}
puts("");
}
return 0;
}