http://poj.org/problem?id=1077
#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[]={1,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 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 print(int s[]){ for(int i=1;i<=9; i++){ printf("%d ", s[i-1]); if(i%3==0) puts(""); } } void invKT(int n, int k){ int s[10]; int t,j; bool visit[10] = {false}; //需要记录该数是否已在前面出现过 for(int i=0; i<n; i++){ t = k/fac[n-i-1]; for(j=0; j<n; j++){ if(!visit[j]){ if(t == 0) break; t--; } } s[i] = j; visit[j] = true; k %= fac[n-i-1]; //cout << j << ","; } print(s); cout << endl; } */ int main() { freopen("in.txt","r",stdin); char str[30]; int i; nod st,ed; while(gets(str)!=NULL) { int cnt=0; 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); //cout << st.n << endl; ko=-1,cnt=0; bfs(st,ed); //双向BFS搜索 int tempP[V]; if(ko!=-1){ //ko表示是交点的方向,如果没改变说明没交点 for(i=re;fa[i]!=i;i=fa[i]){ tempP[cnt] = i; d[cnt++]=p[i]; //下面几行打印路径 } for(i=cnt-1;i>=0;i--){ printf("%c",dir[d[i]]); //invKT(9,tempP[i]); } printf("%c",dir[ko]); for(i=rs;i!=st.n;i=fa[i]) printf("%c",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; }