立体的八数码问题。
普通的DFS和BFS就别想了,迭代加深TLE,而用启发式搜索又想不到合适的启发函数。可发现目标状态有固定的2^8种,而状态转移的方式最多只有4种......所以用双向bfs,应该能解决问题。因为会产生很多重复的状态,所以用hash表判断一下重复的状态。stl的hash会TLE,所以还是手写静态链表哦。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define hashMax 500009
#define tableMax 50000000
using namespace std;
int sta[4][4],tar[4][4],cta[4][4];
int roll_up[7]={0,3,6,1,5,4,2};
int roll_left[7]={0,5,4,6,2,1,3};
int roll_right[7]={0,5,4,6,2,1,3};
int roll_down[7]={0,3,6,1,5,4,2};
int convert(char c)
{
if (c == 'W')
return 1;
if (c == 'R')
return 3;
if (c == 'B')
return 5;
return 8;
}
struct qNode
{
int val;
int step;
qNode()
{
}
qNode(int v,int s)
{
val=v;
step=s;
}
~qNode()
{
}
};
queue<qNode> fq;
queue<qNode> rq;
struct node
{
int v;
int next;
};
struct hashTable
{
node hash[tableMax];
int lh;
void initHash()
{
int i;
lh=hashMax;
for (i=0; i<hashMax; i++)
hash[i].v=-1;
}
bool insert(int v)
{
int tp;
tp=v%hashMax;
if (hash[tp].v == -1)
{
hash[tp].v=v;
hash[tp].next=-1;
return true;
}
while (hash[tp].next != -1)
{
tp=hash[tp].next;
}
hash[tp].next=lh;
hash[lh].v=v;
hash[lh].next=-1;
lh++;
return true;
}
bool find(int v)
{
int tp;
tp=v%hashMax;
if (hash[tp].v == v)
return true;
if (hash[tp].v == -1)
return false;
tp=hash[tp].next;
while (tp != -1)
{
if (hash[tp].v == v)
return true;
tp=hash[tp].next;
}
return false;
}
};
hashTable fhash,rhash;
int getHash(int gh[][4])
{
int cnt,ite,i,j;
ite=1;
cnt=0;
for (i=1; i<=3; i++)
{
for (j=1; j<=3; j++)
{
cnt+=gh[i][j]*ite;
ite*=10;
}
}
return cnt;
}
void dfs(int x,int y)
{
if (y == 4)
{
dfs(x+1,1);
return ;
}
if (x == 4)
{
x=getHash(cta);
rhash.insert(x);
rq.push(qNode(x,0));
return ;
}
cta[x][y]=tar[x][y];
dfs(x,y+1);
cta[x][y]++;
dfs(x,y+1);
}
struct Board
{
int a[4][4];
int x,y;
void printOut()
{
int i,j;
for (i=1; i<=3; i++)
{
for (j=1; j<=3; j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
printf("\n");
}
int toNumber()
{
return getHash(a);
}
void toArray(int tx)
{
int i,j;
for (i=1; i<=3; i++)
{
for (j=1; j<=3; j++)
{
a[i][j]=tx%10;
if (a[i][j] == 8)
{
x=i;
y=j;
}
tx/=10;
}
}
}
bool moveUp()
{
if (x == 3)
return false;
a[x][y]=roll_up[a[x+1][y]];
a[x+1][y]=8;
return true;
}
bool moveDown()
{
if (x == 1)
return false;
a[x][y]=roll_down[a[x-1][y]];
a[x-1][y]=8;
return true;
}
bool moveLeft()
{
if (y == 3)
return false;
a[x][y]=roll_left[a[x][y+1]];
a[x][y+1]=8;
return true;
}
bool moveRight()
{
if (y == 1)
return false;
a[x][y]=roll_right[a[x][y-1]];
a[x][y-1]=8;
return true;
}
bool move(int type)
{
switch(type)
{
case 0:
return moveUp();
case 1:
return moveDown();
case 2:
return moveLeft();
case 3:
return moveRight();
}
return false;
}
};
int bfs()
{
Board b,tb;
qNode qn,tqn;
int cs,tf,tstep,i;
cs=0;
while (cs<30 && !fq.empty() && !rq.empty())
{
// printf("%d\n",cs);
if (fq.size() > rq.size())
{
tstep=rq.front().step;
while (rq.front().step == tstep)
{
qn=rq.front();
b.toArray(qn.val);
for (i=0; i<4; i++)
{
tb=b;
if (tb.move(i) == true)
{
tqn.step=qn.step+1;
tqn.val=tb.toNumber();
if (fhash.find(tqn.val) == true)
return cs+1;
if (rhash.find(tqn.val) == false)
{
rhash.insert(tqn.val);
rq.push(tqn);
}
}
}
rq.pop();
}
}
else
{
tstep=fq.front().step;
while (fq.front().step == tstep)
{
qn=fq.front();
b.toArray(qn.val);
// printf("val=%d\n",qn.val);
for (i=0; i<4; i++)
{
// printf("i=%d\n",i);
tb=b;
if (tb.move(i) == true)
{
tqn.step=qn.step+1;
tqn.val=tb.toNumber();
// tb.printOut();
if (rhash.find(tqn.val) == true)
return cs+1;
if (fhash.find(tqn.val) == false)
{
fq.push(tqn);
fhash.insert(tqn.val);
// printf("tqn.val=%d\n",tqn.val);
}
}
}
fq.pop();
}
}
cs++;
}
return -1;
}
int main()
{
int n,m,i,j;
char c;
while (true)
{
scanf("%d%d",&n,&m);
if (n == 0 || m == 0)
break;
i=n;
n=m;
m=i;
rhash.initHash();
fhash.initHash();
while (!rq.empty()) rq.pop();
while (!fq.empty()) fq.pop();
for (i=1; i<=3; i++)
{
for (j=1; j<=3; )
{
c=getchar();
if (c >= 'A' && c <= 'Z')
{
tar[i][j]=convert(c);
sta[i][j]=1;
j++;
}
}
}
sta[n][m]=8;
i=getHash(sta);
dfs(1,1);
if (rhash.find(i) == true)
{
printf("0\n");
continue;
}
fhash.insert(i);
fq.push(qNode(i,0));
printf("%d\n",bfs());
}
}