双向BFS

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;
 }


你可能感兴趣的:(双向BFS)