八数码第四境界——暴力反向BFS+康托展开判重+打表+回溯记录路径

(请先看前面3重境界)

由于第三重境界要开一个vector来嵌套许多vector来记录路径,那绝对是开销很大。所以我们采用回溯记录路径。


思路:

原来我们是采用康托展开,比如求出12345678x在全排列的第几个(这里无疑是第一个),用来判断这种状态是否已经到达过了,这里就是vis[1]=1代表已经访问过,vis[1]=0代表未访问过。在每次访问以后都置为1。而现在我们这里不一样了。我们存放的是层数。我们这里想要的是路径吧?所以说这里指的就是在这条路径上的第几个,我们的做法就是在最后找到以后,根据这个第几个,来逐一找到上一个,直到找到终点。以前我们每种状态维护的是一个路径,我们这里只需要维护一个操作就可以了。只要我们能把每种状态的路径,和上一种状态的路径,想办法关联起来,就可以了。


用来找到关联的结构体:

1.  struct res  

2.  {  

3.      int now,fa;  

}res[N]; 

now存放的就是当前的操作(上下左右),fa就是这条路径上上一个状态的操作在这个res数组中存放的地方。就比如说我现在是这个数组的第10个,我的操作是上,我的fa是7,就代表我上一个操作被存放在了7,我们不断去取即可。所以我们一旦让一个点入栈了,也同时会在这个数组的尾端添加一个。赋予他当前的操作是什么,以及这条路径上上一个操作所存放的位置。这个怎么得知呢?因为我们就是通过上一种状态得出下一种状态的,所以我们只需要在上一种状态得出下一种状态的过程中,把他上一种状态所在这个数组中的位置给他,交给他去维护了。所以我们可以得知,这个res数组,并不是有序的。什么意思呢?并不是说这个状态的操作在这里,下一个状态的操作在这个数组的下一个位置,而是通过fa来进行关联。

上个图:


此外,我们上面讲的康托展开,vis[某个节点对应的康托值] = 这个res集合中的某一位,再以此为依据就能回溯出之前的路径了。


讲了这么多理论,具体看看细化的实现。

1.  if((h.index+1)%3!=0)  

2.          {  

3.              c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;  

4.              h.index++;  

5.              res[cnt].now=4;res[cnt].fa=h.pos;h.pos=cnt;cnt++;  

6.              int t=KT(h.str);  

7.              if(vis[t]==-1)  

8.              {  

9.                  vis[t]=cnt-1;  

10.                 q.push(h);  

11.             }  

12.         }  

if语句判断如果不是在最后一列,那就肯定就可以右移。

下一行,和右边那个数进行交换。

h.index指的是x在状态中的位置

res[cnt].now=4,4指代的是右移操作

res[cnt].fa=h.pos这个指的是你上一个状态所在这个res数组的位置赋给你当前状态去维护

h.pos=cnt这是你当前状态所在这个res数组的位置

cnt++你插入了一个数,自然要++,不然接下来还用不用了

最后如果这个位置没有访问过,那么这个状态在vis中的值,也被置为和你当前h.pos位置一样的值。为什么这里也要作文章,因为最后你输出的时候你肯定要根据所要求的结果在res中定位,那你定位的依据是什么?只能以序列通过求康托值得出在vis中的位置,再去取得这个值。

1.  if(vis[t]!=-1)  

2.          {  

3.              t = vis[t];  

4.              while(res[t].now!=-1)  

5.              {  

6.                  if(res[t].now==1)printf("d");  

7.                  if(res[t].now==2)printf("u");  

8.                  if(res[t].now==3)printf("r");  

9.                  if(res[t].now==4)printf("l");  

10.                 t=res[t].fa;  

11.             }  

12.         }  

13.         else  

14.             printf("unsolvable");  

如果vis[t]!=-1,那么就是这种状态肯定是有的,而我们在这个里面存储了他在res中的位置,所以再通过fa一步步回推,得出了序列。


全部代码

  1. #define N 512345  
  2.   
  3. char ss[10];  
  4. struct node  
  5. {  
  6.     char str[10];  
  7.     int pos;  
  8.     int index;  
  9. };  
  10. struct res  
  11. {  
  12.     int now,fa;  
  13. }res[N];  
  14. int vis[N];  
  15. int  fac[] = {1,1,2,6,24,120,720,5040,40320};  
  16. int over,cnt;  
  17. int ans[N];  
  18. int KT(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值