双向BFS

来源:互联网 发布:四种会话跟踪技术php 编辑:程序博客网 时间:2024/05/01 16:19

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


原创粉丝点击