#include <iostream>
#include <stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef int state[9];
const int maxstate=1000001;
state goal,st[maxstate];
int dis[maxstate];
int endsteps;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
void init_lookup_table();
int try_to_insert(int);
int bfs(){
init_lookup_table();
int front=1,rear=2;
while(front<rear){
state &s=st[front];
if(memcmp(goal,s,sizeof(s))==0){endsteps=front;return front;}
int z;
for(z=0;z<9;z++){
if(!s[z]){break;}
}
int x=z/3;
int y=z%3;
for(int i=0;i<4;i++){
int newx=x+dx[i];
int newy=y+dy[i];
int newz=newx*3+newy;
if(newx>=0&&newx<3&&newy>=0&&newy<3){
state &t=st[rear];
memcpy(&t,&s,sizeof(s));
t[newz]=s[z];
t[z]=s[newz];
dis[rear]=dis[front]+1;
if(try_to_insert(rear))rear++;}
}
front++;
}
return 0;
}
const int hashsize=1000003;
int head[hashsize],Next[maxstate];
void init_lookup_table(){
memset(head,0,sizeof(head));
}
int Hash(state &s){
long long sum=0;
for(int i=0;i<9;i++){
sum=sum*10+s[i];
}
return sum%hashsize;
}
int try_to_insert(int s){
int h=Hash(st[s]);
int u=head[h];
while(u){
if(memcmp(st[u],st[s],sizeof(st[s]))==0)return 0;
u=Next[u];
}
Next[s]=head[h];
head[h]=s;
return 1;
}
int main(){
for(int i=0;i<9;i++)cin>>st[1][i];
for(int i=0;i<9;i++)cin>>goal[i];
int ans=bfs();
if(ans>0){
cout<<dis[ans]<<endl;
}
else {cout<<"-1"<<endl;}
system("pause");
return 0;
}
↑①暴力BFS+哈希表版(可自定义初状态和末状态,自动计算所需要的最短步数,如果无法实现则输出-1)
↓②双向BFS+输出最佳方案版(末状态固定,默认为123456780)(从左到右,从上到下,0代表空格)
注意:输入格式为一个字符串,即一个9位数,空格默认用x表示
如:第一行为123第二行为456第三行为7+空格+8 ,则输入数据应该为 1234567x8
如果不能实现则输出“unsolvable",存在最佳路径时输出要走的所有步数(在源码上优化了一下,本来代码只输出步数)
#include<cstdio> //双向BFS poj 1077 16ms
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
const int V=362882;
struct nod{
int n,x; //n表示康拓展开的值,x表示9的位置。
int m[9]; //记录状态
};
int fac[]={0,1,2,6,24,120,720,5040,40320}; //阶乘表
int dx[]={1,-1,0,0},dy[]={0,0,-1,1},tr[]={1,0,3,2}; //tr用于转向
char dir[]="dulr";
int init[3][3];
int vir[2][V],p[V],fa[V],d[V],re,rs,ko;
queue<nod> q[2]; //两个队列
void bfs(nod st,nod ed);
int exp(nod s,int k);
int cato(nod a);
void output(char s){
int x=0,y=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(init[i][j]==0){x=i;y=j;break;}
}
}
switch(s){
case 'l':
init[x][y]=init[x][y-1];
init[x][y-1]=0;
break;
case 'r':
init[x][y]=init[x][y+1];
init[x][y+1]=0;
break;
case 'u':
init[x][y]=init[x-1][y];
init[x-1][y]=0;
break;
case 'd':
init[x][y]=init[x+1][y];
init[x+1][y]=0;
break;
}
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
cout<<init[i][j]<<" ";
}
cout<<endl;
}
}
int main()
{
// freopen("in.in","r",stdin);
char str[30]; int i;
nod st,ed;
while(gets(str)!=NULL)
{
int cnt=0;
init[0][0]=str[0]-'0';
init[0][1]=str[1]-'0';
init[0][2]=str[2]-'0';
init[1][0]=str[3]-'0';
init[1][1]=str[4]-'0';
init[1][2]=str[5]-'0';
init[2][0]=str[6]-'0';
init[2][1]=str[7]-'0';
init[2][2]=str[8]-'0';
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(init[i][j]=='x'-'0'){init[i][j]=0;
break;}
}
}
for(i=0;i<9;i++){
st.m[i]=i+1; } //读取初始的起点和终点
for(i=0;i<strlen(str);i++){
if(str[i]=='x') ed.x=cnt, ed.m[cnt++]=9;
if(str[i]>='1'&&str[i]<='8') ed.m[cnt++]=str[i]-'0';
}
ed.n=cato(ed);
st.x=8; st.n=cato(st);
ko=-1,cnt=0;
bfs(st,ed); //双向BFS搜索
if(ko!=-1){ //ko表示是交点的方向,如果没改变说明没交点
for(i=re;fa[i]!=i;i=fa[i]) d[cnt++]=p[i]; //下面几行打印路径
for(i=cnt-1;i>=0;i--) {printf("%c\n",dir[d[i]]);output(dir[d[i]]);}
printf("%c\n",dir[ko]);output(dir[ko]);
for(i=rs;i!=st.n;i=fa[i]) {printf("%c\n",dir[tr[p[i]]]);output(dir[tr[p[i]]]);}
}
else printf("unsolvable");
printf("\n");
}
return 0;
}
int cato(nod a) //康拓展开
{
int i,j,k,sum=0;
for(i=0;i<9;i++){
for(j=i+1,k=0;j<9;j++) if(a.m[j]<a.m[i]) k++;
sum+=k*fac[8-i];
}
return sum;
}
void bfs(nod st,nod ed)
{
memset(fa,-1,sizeof(fa));
memset(vir,0,sizeof(vir));
q[0].push(st); q[1].push(ed); //起点终点入队
vir[0][st.n]=1; vir[1][ed.n]=1;
fa[st.n]=st.n; fa[ed.n]=ed.n;
while(!q[0].empty()||!q[1].empty())
{
nod ss=q[0].front(); q[0].pop();
nod ee=q[1].front(); q[1].pop();
if(exp(ss,0)||exp(ee,1)) break;
}
}
int exp(nod s,int k) //扩展函数,即对s点寻找下一层的点
{
int i,t,sn=s.x,sx=sn/3,sy=sn%3,nn;
nod nex;
for(i=0;i<4;i++){
int nx=sx+dx[i],ny=sy+dy[i];
if(nx<3&&nx>=0&&ny<3&&ny>=0){
nex=s;
nn=nx*3+ny;
t=nex.m[sn]; nex.m[sn]=nex.m[nn]; nex.m[nn]=t;
nex.n=cato(nex);
nex.x=nn; //求下一个可能扩展的点
if(vir[k][nex.n]) continue;
if(vir[k^1][nex.n]==1) { //找到交点返回1,k代表是从起点还是从终点的路径
if(k) { ko=i; re=s.n; rs=nex.n; }
else { ko=tr[i]; re=nex.n; rs=s.n; }
return 1;
} vir[k][nex.n]=1;
q[k].push(nex); //可扩展,入队。
fa[nex.n]=s.n;
p[nex.n]=i;
}
}
return 0;
}