八数码第五境界——双向BFS+康托展开判重+回溯记录路径

(请先看前4大境界)

这里较上一境界,就是把反向的BFS,弄成了双向的BFS。先不说算法的优劣,就光这个双向的BFS,就是指的记录和学习的。


很简单,在结合之前所学的基础上,把单向扩展成双向即可。


结构体

  1. struct node  
  2. {  
  3.     char str[10];  
  4.     int mark,num;  
  5.     int index,hashnum;  
  6. };  
这里的结构体,增加了一个mark,用来判断他是从终点开始bfs的(mark=0)还是从我们所要求的起点开始bfs的(mark=1)。


回溯路径结构体数组,就需要多开一个

  1. struct res  
  2. {  
  3.     int fa,now;  
  4. }res1[N],res2[N];  

访问与否,也需要多开一个

  1. int vis1[N],vis2[N];  

先让终点状态入队列

  1. g.mark=0;g.num=0;g.index=8;  
  2.     vis1[KT(g.str)]=0;  
  3.     q.push(g);

再让起点状态入队列

  1. for(int i=0;i<9;i++)  
  2.         g.str[i]=ss[i];  
  3.     g.mark=1;g.num=0;g.index=temp;  
  4.     vis2[KT(g.str)]=0;  
  5.     q.push(g);  

所以这里我们得知了,我们虽然是bfs,但是仍旧共享一个队列,我们一开始,也是将两个开始状态都入队。


如果找到,应该进行的判断

  1.        if(g.mark==0&&vis2[t]!=-1)  
  2.         {  
  3.             ans1=g.num;  
  4.             ans2=vis2[t];  
  5.             return true;  
  6.         }  
  7.         if(g.mark==1&&vis1[t]!=-1)  
  8.         {  
  9.             ans2=g.num;  
  10.             ans1=vis1[t];  
  11.             return true;  
  12.         }  
g.mark==0指代的是从终点开始bfs的,vis2[t]!=-1指代的是这个状态,从起点开始的bfs他走到过。(所以这里用的vis2)


bfs流程

  1.         h=g;  
  2.         if((h.index+1)%3!=0)  
  3.         {  
  4.             c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;  
  5.             h.index++;  
  6.             if(!h.mark){res1[cnt1].now=4;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}  
  7.             else {res2[cnt2].now=4;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}  
  8.             int t=KT(h.str);  
  9.             if(vis1[t]==-1&&!h.mark)  
  10.             {  
  11.                 vis1[t]=h.num;  
  12.                 q.push(h);  
  13.                 sum1++;  
  14.             }  
  15.             else if(vis2[t]==-1&&h.mark)  
  16.             {  
  17.                 vis2[t]=h.num;  
  18.                 q.push(h);  
  19.                 sum2++;  
  20.             }  
  21.         }  
首先第一个if,意思就是不为第三列,那就是前面两列,所以自然肯定可以右移。

c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c; 这个就是右移操作

h.index++; 指代h状态中x所在的位置

接下来的那个if,!h.mark,那意思就是为0的情况,那就是从终点开始的bfs。

if里面的内容就是用来回溯路径的。

else就是代表从起点开始的bfs。

这个时候h较g已经发生了改变,再通过康托展开取得值。

接下来的if。如果这个状态再vis1中未曾出现过且现在是起点开始的bfs,那就把这个状态置为已访问,再把这个新的状态入队列。

最后的sum1++就耐人寻味了。


我们先找到sum所在的地方

声明处

 sum1=sum2=1;  


  1. while(!q.empty())  
  2.     {  
  3.         g=q.front();q.pop();  
  4.         int t = KT(g.str);  
  5.         if(g.mark==0)sum1--;  
  6.         else sum2--;  

然后在每次入队列的的时候都会减1。所以这个num1就指代了你当前队列中,属于你终点开始的bfs在队列中还剩下几个元素。


最后的终止条件

  1. if(sum1==0||sum2==0)  
  2.             return false;  

如果其中一个的元素出光了,那就代表返回false,退出了。为什么其中一个元素出光了就代表没机会了呢?难道不能之后从另一个点出发的bfs又走回到你这个路径上来了呢?其实我想说,仅仅这样还限定的不严格。不过我们就先谈谈这个。我们先假设,其中一个bfs所有情况遍历了,另一个bfs在随后走到了这条路上来。那么我想问,这是否意味着另一个bfs总有办法走到之前的bfs的路上来,也就证明他们是相通的。但是第一个bfs走光了,那肯定也代表他把能走相通的路都走过了!所以这是矛盾的。具体什么时候才是真正的没机会了呢?不必深究了。


全部代码

  1. #define N 512345  
  2.   
  3. char ss[10];  
  4. struct node  
  5. {  
  6.     char str[10];  
  7.     int mark,num;  
  8.     int index,hashnum;  
  9. };  
  10. struct res  
  11. {  
  12.     int fa,now;  
  13. }res1[N],res2[N];  
  14. int vis1[N],vis2[N];  
  15. int  fac[] = {1,1,2,6,24,120,720,5040,40320};  
  16. int over,ans1,ans2,sum1,sum2,cnt1,cnt2;  
  17. int hehe[N];  
  18. int KT(char ss[])  
  19. {  
  20.     int i, j, t, sum;  
  21.     int s[10];  
  22.     for(i=0;i<9;i++)  
  23.     {  
  24.         if(ss[i]=='x')  
  25.             s[i]=0;  
  26.         else  
  27.             s[i]=ss[i]-'0';  
  28.     }  
  29.     sum = 0;  
  30.     for (i=0; i<9; i++)  
  31.     {  
  32.         t = 0;  
  33.         for (j=i+1; j<9; j++)  
  34.             if (s[j] < s[i])  
  35.                 t++;  
  36.         sum += t*fac[9-i-1];  
  37.     }  
  38.     return sum+1;  
  39. }  
  40. bool bfs(char ss[], int temp)  
  41. {  
  42.     char c;  
  43.     queue<node> q;  
  44.     while(!q.empty())q.pop();  
  45.   
  46.     node g,h;  
  47.     for(int i=0;i<8;i++)  
  48.         g.str[i]=i+1+'0';  
  49.     g.str[8]='x';g.str[9]='\0';  
  50.     g.mark=0;g.num=0;g.index=8;  
  51.     vis1[KT(g.str)]=0;  
  52.     q.push(g);  
  53.     for(int i=0;i<9;i++)  
  54.         g.str[i]=ss[i];  
  55.     g.mark=1;g.num=0;g.index=temp;  
  56.     vis2[KT(g.str)]=0;  
  57.     q.push(g);  
  58.     sum1=sum2=1;  
  59.     cnt1=cnt2=1;  
  60.   
  61.     while(!q.empty())  
  62.     {  
  63.         g=q.front();q.pop();  
  64.         int t = KT(g.str);  
  65.         if(g.mark==0)sum1--;  
  66.         else sum2--;  
  67.         if(g.mark==0&&vis2[t]!=-1)  
  68.         {  
  69.             ans1=g.num;  
  70.             ans2=vis2[t];  
  71.             return true;  
  72.         }  
  73.         if(g.mark==1&&vis1[t]!=-1)  
  74.         {  
  75.             ans2=g.num;  
  76.             ans1=vis1[t];  
  77.             return true;  
  78.         }  
  79.         h=g;  
  80.         if((h.index+1)%3!=0)  
  81.         {  
  82.             c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;  
  83.             h.index++;  
  84.             if(!h.mark){res1[cnt1].now=4;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}  
  85.             else {res2[cnt2].now=4;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}  
  86.             int t=KT(h.str);  
  87.             if(vis1[t]==-1&&!h.mark)  
  88.             {  
  89.                 vis1[t]=h.num;  
  90.                 q.push(h);  
  91.                 sum1++;  
  92.             }  
  93.             else if(vis2[t]==-1&&h.mark)  
  94.             {  
  95.                 vis2[t]=h.num;  
  96.                 q.push(h);  
  97.                 sum2++;  
  98.             }  
  99.         }  
  100.         h=g;  
  101.         if(h.index%3!=0)  
  102.         {  
  103.             c=h.str[h.index];h.str[h.index]=h.str[h.index-1];h.str[h.index-1]=c;  
  104.             h.index--;  
  105.             if(!h.mark){res1[cnt1].now=3;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}  
  106.             else {res2[cnt2].now=3;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}  
  107.             int t=KT(h.str);  
  108.             if(vis1[t]==-1&&!h.mark)  
  109.             {  
  110.                 vis1[t]=h.num;  
  111.                 q.push(h);  
  112.                 sum1++;  
  113.             }  
  114.             else if(vis2[t]==-1&&h.mark)  
  115.             {  
  116.                 vis2[t]=h.num;  
  117.                 q.push(h);  
  118.                 sum2++;  
  119.             }  
  120.         }  
  121.         h=g;  
  122.         if(h.index<6)  
  123.         {  
  124.             c=h.str[h.index];h.str[h.index]=h.str[h.index+3];h.str[h.index+3]=c;  
  125.             h.index+=3;  
  126.             if(!h.mark){res1[cnt1].now=2;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}  
  127.             else {res2[cnt2].now=2;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}  
  128.             int t=KT(h.str);  
  129.             if(vis1[t]==-1&&!h.mark)  
  130.             {  
  131.                 vis1[t]=h.num;  
  132.                 q.push(h);  
  133.                 sum1++;  
  134.             }  
  135.             else if(vis2[t]==-1&&h.mark)  
  136.             {  
  137.                 vis2[t]=h.num;  
  138.                 q.push(h);  
  139.                 sum2++;  
  140.             }  
  141.         }  
  142.         h=g;  
  143.         if(h.index>2)  
  144.         {  
  145.             c=h.str[h.index];h.str[h.index]=h.str[h.index-3];h.str[h.index-3]=c;  
  146.             h.index-=3;  
  147.             if(!h.mark){res1[cnt1].now=1;res1[cnt1].fa=h.num;h.num=cnt1;cnt1++;}  
  148.             else {res2[cnt2].now=1;res2[cnt2].fa=h.num;h.num=cnt2;cnt2++;}  
  149.             int t=KT(h.str);  
  150.             if(vis1[t]==-1&&!h.mark)  
  151.             {  
  152.                 vis1[t]=h.num;  
  153.                 q.push(h);  
  154.                 sum1++;  
  155.             }  
  156.             else if(vis2[t]==-1&&h.mark)  
  157.             {  
  158.                 vis2[t]=h.num;  
  159.                 q.push(h);  
  160.                 sum2++;  
  161.             }  
  162.         }  
  163.         if(sum1==0||sum2==0)  
  164.             return false;  
  165.     }  
  166.     return false;  
  167. }  
  168. int main()  
  169. {  
  170.     int i,j,k,kk,t,x,y,z;  
  171.     while(scanf("%s",ss)!=EOF)  
  172.     {  
  173.         if(ss[0]=='x')x=0;  
  174.         for(i=1;i<9;i++)  
  175.         {  
  176.             scanf("%s",ss+i);  
  177.             if(ss[i]=='x') x=i;  
  178.         }  
  179.   
  180.         ans1=ans2=-1;  
  181.         memset(vis1,-1,sizeof(vis1));  
  182.         memset(vis2,-1,sizeof(vis2));  
  183.         res1[0].now=res2[0].now=-1;  
  184.   
  185.         if(bfs(ss,x))  
  186.         {  
  187.             x=0;  
  188.             if(res2[ans2].now==-1&&res1[ans1].now==-1)  
  189.             {  
  190.                 printf("lr\n");  
  191.                 continue;  
  192.             }  
  193.             while(res2[ans2].now!=-1)  
  194.             {  
  195.                 hehe[x++]=res2[ans2].now;  
  196.                 ans2=res2[ans2].fa;  
  197.             }  
  198.             for(i=x-1;i>=0;i--)  
  199.             {  
  200.                 if(hehe[i]==1)printf("u");  
  201.                 if(hehe[i]==2)printf("d");  
  202.                 if(hehe[i]==3)printf("l");  
  203.                 if(hehe[i]==4)printf("r");  
  204.             }  
  205.             while(res1[ans1].now!=-1)  
  206.             {  
  207.                 if(res1[ans1].now==1)printf("d");  
  208.                 if(res1[ans1].now==2)printf("u");  
  209.                 if(res1[ans1].now==3)printf("r");  
  210.                 if(res1[ans1].now==4)printf("l");  
  211.                 ans1=res1[ans1].fa;  
  212.             }  
  213.         }  
  214.         else  
  215.             printf("unsolvable");  
  216.         printf("\n");  
  217.     }  
  218.     return 0;  
  219. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值