poj 1077 Eight

// 题意:八数码问题,需要打印路径
#include <iostream> // BFS 康托展开判重
#include <string.h>

#include <stack>
using namespace std;
typedef int State[9];
const int MAXSTATE=1000000;
State st[MAXSTATE],goal;
int fa[MAXSTATE],mv[MAXSTATE];
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//9!表 
int cantor(State node) //康托展开,求一个数(以数组方式给出)在全排列中的位置
{

int temp,num=1;
for(int i=0;i<9;++i)
{
temp=0;
for(int j=i+1;j<9;++j)
if(node[j]<node[i])
temp++;
num+=fac[8-i]*temp;
}
return num;
}
bool vis[MAXSTATE];
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
char name[]="udlr";
void bfs()
{
vis[cantor(st[0])]=1;
int ok=0,front=0,rear=1;
while(front<rear)
{
State& s=st[front]; //引用才能直接赋值
if(memcmp(goal,s,sizeof(s))==0)

{
stack<char> path;
int u=front;
while(u>0)
{
path.push(name[mv[u]]);
u=fa[u];
}
while(!path.empty()) //打印路径
{

printf("%c",path.top());
path.pop();
}
printf("\n");
ok=1;
break;
}
int z;
for(z=0;z<9;++z)
if(!s[z])
break;
int x=z/3,y=z%3;
for(int d=0;d<4;++d)
{
int newx=x+dx[d];
int newy=y+dy[d];
int newz=newx*3+newy;
if(newx>=0&&newx<3&&newy>=0&&newy<3)
{
State& t=st[rear]; //引用,下面改变t[]就会作用于st[rear]
memcpy(t,s,sizeof(s));

t[newz]=s[z];
t[z]=s[newz];
int id=cantor(t);
if(!vis[id])
{
vis[id]=1;
mv[rear]=d;
fa[rear]=front;
rear++;
}
}
}
front++;
}
if(!ok)
printf("unsolvable\n");
}
int main()
{
char ch;
for(int i=0;i<9;++i)
{
cin>>ch;
if(ch=='x')
st[0][i]=0;
else
st[0][i]=ch-'0';
}
for(int i=0;i<9;++i)
goal[i]=(i+1)%9;
memset(vis,0,sizeof(vis));
bfs();
return 0;
}

 

 

 

 

双向BFS
        
// 题意:八数码问题,需要打印路径
#include <iostream> // 双向BFS 康托展开判重 耗时仅 16ms
#include <string.h>
#include <queue>
using namespace std;
typedef int State[9];
const int MAXSTATE=1000000;
State st1[MAXSTATE],st2[MAXSTATE];
int fa1[MAXSTATE],mv1[MAXSTATE],fa2[MAXSTATE],mv2[MAXSTATE];
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//9!表 
int cantor(State node) //康托展开,求一个数(以数组方式给出)在全排列中的位置
{
int temp,num=1;
for(int i=0;i<9;++i)
{
temp=0;
for(int j=i+1;j<9;++j)
if(node[j]<node[i])
temp++;
num+=fac[8-i]*temp;
}
return num;
}
int vis[MAXSTATE],pos1[MAXSTATE],pos2[MAXSTATE]; //vis数组初始化为 0
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
char name1[]="udlr",name2[]="durl"; //name2与name1刚好相反

void bfs()
{
if(memcmp(st1[0],st2[0],sizeof(st1[0]))==0)
{
printf("\n");
return;
}
pos1[cantor(st1[0])]=0;
pos2[cantor(st2[0])]=0;
vis[cantor(st1[0])]=1;
vis[cantor(st2[0])]=2;
int ok=0,front1=0,rear1=1,front2=0,rear2=1,dest;

while(front1<rear1||front2<rear2)
{

//正向搜索
if(front1<rear1)
{
State& s=st1[front1]; //引用才能直接赋值
int z;
for(z=0;z<9;++z)
if(!s[z])
break;
int x=z/3,y=z%3;
for(int d=0;d<4;++d)
{
int newx=x+dx[d];
int newy=y+dy[d];
int newz=newx*3+newy;
if(newx>=0&&newx<3&&newy>=0&&newy<3)
{
State& t=st1[rear1]; //引用,下面改变t[]就会作用于st[rear]
memcpy(t,s,sizeof(s));
t[newz]=s[z];
t[z]=s[newz];
int id=cantor(t);
if( vis[id] != 1 ) //该点还未正向搜索过
{
mv1[rear1]=d;
fa1[rear1]=front1;
pos1[id]=rear1; //pos记录该数组的康托展开值cantor(t)的下标,在打印路径时会用到
rear1++;
if( vis[id] == 0 )
{
vis[id] = 1 ; //正向搜索标记为 1
}
else // vis[id] == 2 ,说明正向和反向搜索发生相遇
{
dest=id;
ok=1;
break;
}
}
}
}
front1++;

if(ok)
break;
}

//反向搜索,与正向搜索类似
if(front2<rear2)
{
State& s=st2[front2]; //引用才能直接赋值
int z;
for(z=0;z<9;++z)
if(!s[z])
break;
int x=z/3,y=z%3;
for(int d=0;d<4;++d)
{
int newx=x+dx[d];
int newy=y+dy[d];
int newz=newx*3+newy;
if(newx>=0&&newx<3&&newy>=0&&newy<3)
{
State& t=st2[rear2]; //引用,下面改变t[]就会作用于st[rear]
memcpy(t,s,sizeof(s));
t[newz]=s[z];
t[z]=s[newz];
int id=cantor(t);
if( vis[id] != 2 ) //该点还未反向搜索过
{
mv2[rear2]=d;
fa2[rear2]=front2;
pos2[id]=rear2;
rear2++;
if( vis[id] == 0 )
{
vis[id] = 2 ; //反向搜索标记为 2
}
else // vis[id] == 1 ,说明正向和反向搜索发生相遇
{
dest=id;
ok=1;
break;
}
}
}
}
front2++;

if(ok)
break;
}

}

if(ok) //打印路径
{
int r1=pos1[dest],r2=pos2[dest];
deque<char> ans;
while(r2>0)
{
ans.push_back(name2[mv2[r2]]);
r2=fa2[r2];
}
while(r1>0)
{
ans.push_front(name1[mv1[r1]]);
r1=fa1[r1];
}

for(int i=0;i<ans.size();++i)
printf("%c",ans[i]);
printf("\n");
}
else
printf("unsolvable\n"); //说明正向和反向搜索没有相遇
}
int main()
{
char ch;
for(int i=0;i<9;++i)
{
cin>>ch;
if(ch=='x')
st1[0][i]=0;
else
st1[0][i]=ch-'0'; //正向搜索由起点拓展起
}
for(int i=0;i<9;++i)
st2[0][i]=(i+1)%9; //反向搜索由终点拓展起
memset(vis,0,sizeof(vis));
bfs();
return 0;
}

 

posted on 2011-07-22 16:58  sysu_mjc  阅读(117)  评论(0编辑  收藏  举报

导航