八数码第八境界——IDA*+逆序数判无解

来源:互联网 发布:understand mac注册码 编辑:程序博客网 时间:2024/06/06 03:58

(请先看前面7大境界)


IDA*是什么?

它已经不再像A*一样通过bfs+优先队列+曼哈顿距离3者结合来做。

它是通过曼哈顿距离,求出最大搜索深度,还是和上篇文章的例子一样来说。


我们这里使用的是曼哈顿距离。

我们希望的路径假设是

4 8 7

1 2 x

5 6 3

我们的结束路径是

1 2 3

4 5 6

7 8 x

我们看到希望的路径和假设的路径1,相差1个位置,

2,相差1个位置,3相差2个位置。。。

就把所有的相差的位置的横向距离和纵向距离加起来求和,就粗略得出了我们至少应该移动的距离。之后我们在优先队列里,这个距离就是我们判断的依据。


通过这种形式求出了曼哈顿距离,也是我们求出的最大搜索深度。并且我们将会通过最大搜索深度+DFS的方法来搜索。如果超过这个最大搜索深度,就剪枝了。如果在这个最大搜索深度内搜索不到,那就增加这个搜索深度。怎么增加呢?根据那些超出最大搜索深度的深度,找到最小的超出最大搜索深度的深度,以此作为新的深度来进行dfs。所以我们的做法和前7大境界(都是依赖bfs的做法)有了很大的区别。



接下来就仔细讲讲具体细节。

  1. int dfs(int now,int num,int pos)  
  2. {  
  3.     char c;  
  4.     int val = len(s);  
  5.     if(val+num>sum)  
  6.         return val+num;  
  7.     res[num]=pos;  
这是dfs的一部分代码。

int val=len(s)就是求出剩下的曼哈顿距离。

看看这个if语句,如果剩下的曼哈顿距离和当前走出的距离之和大于sum,就剪枝了。返回这个超出搜索距离的距离。

sum是什么呢?就是我们当前的最大搜索距离。

还有int dfs(int now,int num,int pos) 。now是当前的x在数组中哪个位置。num是当前已走出去的步数。pos是当前的操作(上下左右)。

res[num]=pos;  这里就是把操作存进去。当然之前可能有存放过,而且在那个方向失败了,不过这不影响什么。


看一下具体的dfs

  1.  if(pos!=3&&(now+1)%3!=0)  
  2.     {  
  3.         c=s[now];s[now]=s[now+1];s[now+1]=c;  
  4.         tmp2=dfs(now+1,num+1,4);  
  5.         if(ans)return tmp2;  
  6.         tmp1=min(tmp1,tmp2);  
  7.         c=s[now];s[now]=s[now+1];s[now+1]=c;  
  8.     }  
看一下判断条件,如果pos是3,就代表是左移得到当前状态的。那自然就不能向右移,不然就是走回头路了。

还有后面一个条件就是如果不在最后一列,那自然可以向右移动。

c=s[now];s[now]=s[now+1];s[now+1]=c;就代表右移一格

tmp2=dfs(now+1,num+1,4);继续bfs深入,x所在位置右移一格,步数+1.操作为右移,带着这个去继续走

if(ans)return tmp2;这个就是代表如果ans=1,我们后面会知道,如果ans=1就代表找到了,要终止其他的bfs,不然gg。

tmp1=min(tmp1,tmp2);就耐人寻味了。我们需要从最后一层开始思考。最后一层肯定就是剪枝的情况。当我们当前步数+曼哈顿距离超过当前限定的搜索步数,那就返回这个更长的搜索步数。tmp1在这里就被赋值成了这个更长的搜索步数。但是倒数第二层有3个方向可以走(排除刚刚过来的那个方向),所以我们这样做是在这3个方向里取得最小更长的搜索步数并返回。那么如果没找到,返回到一开始就是会返回最小的更长的搜索深度。再看看上面的return tmp2。返回的是找到情况下的搜索深度,在tmp1=min(tmp1,tmp2); 中肯定是最小的。直到到一开始,返回了我们找到的深度。并且另外的bfs不再进行。直接从我们记录路径的数组中直接从0读到当前搜索深度就是我们需要的路径了。


再看看我们对于dfs的调用方法

  1. void IDAStar(int now)  
  2. {  
  3.     sum=len(s);ans=0;  
  4.     while(!ans)  
  5.         sum=dfs(now,0,0);  
  6. }  
如果dfs没找到,那最后会返回一个新的深度,更新了sum。然后接下来找的时候,进行剪枝的比较就是带着这个更新后的sum了。所以是以这样一种方式实现了,“如果这个搜索深度找不到,就找到更长的搜索深度,取最小,返回。然后继续找,知道找到为止。


全部代码

  1. #define N 1123  
  2.   
  3. char s[10];  
  4. int res[N],sum,ans;  
  5. bool inverse(char ss[])  
  6. {  
  7.     int t=0,x,y;  
  8.     for(int i=1;i<9;i++)  
  9.         for(int j=0;j<i;j++)  
  10.         {  
  11.             if(ss[j]=='x')continue;  
  12.             else x=ss[j]-'0';  
  13.             if(ss[i]=='x')continue;  
  14.             else y=ss[i]-'0';  
  15.             if(x>y)  
  16.                 t++;  
  17.         }  
  18.     if(t&1)  
  19.         return true;  
  20.     return false;  
  21. }  
  22. int len(char str[])  
  23. {  
  24.     int ans=0;  
  25.     for(int i=0;i<9;i++)  
  26.     {  
  27.         if(str[i]!='x')  
  28.             ans+=abs(i/3-(str[i]-'0'-1)/3)+abs(i%3-((str[i]-'0')-1)%3);  
  29.         else  
  30.             ans+=(2-i/3)+(2-i%3);  
  31.     }  
  32.     return ans;  
  33. }  
  34. int dfs(int now,int num,int pos)  
  35. {  
  36.     char c;  
  37.     int val = len(s);  
  38.     if(val+num>sum)  
  39.         return val+num;  
  40.     res[num]=pos;  
  41.     if(val==0)  
  42.     {  
  43.         ans=1;  
  44.         return num;  
  45.     }  
  46.     int tmp1=INF,tmp2;  
  47.     if(pos!=3&&(now+1)%3!=0)  
  48.     {  
  49.         c=s[now];s[now]=s[now+1];s[now+1]=c;  
  50.         tmp2=dfs(now+1,num+1,4);  
  51.         if(ans)return tmp2;  
  52.         tmp1=min(tmp1,tmp2);  
  53.         c=s[now];s[now]=s[now+1];s[now+1]=c;  
  54.     }  
  55.     if(pos!=4&&now%3!=0)  
  56.     {  
  57.         c=s[now];s[now]=s[now-1];s[now-1]=c;  
  58.         tmp2=dfs(now-1,num+1,3);  
  59.         if(ans)return tmp2;  
  60.         tmp1=min(tmp1,tmp2);  
  61.         c=s[now];s[now]=s[now-1];s[now-1]=c;  
  62.     }  
  63.     if(pos!=1&&now<6)  
  64.     {  
  65.         c=s[now];s[now]=s[now+3];s[now+3]=c;  
  66.         tmp2=dfs(now+3,num+1,2);  
  67.         if(ans)return tmp2;  
  68.         tmp1=min(tmp1,tmp2);  
  69.         c=s[now];s[now]=s[now+3];s[now+3]=c;  
  70.     }  
  71.     if(pos!=2&&now>2)  
  72.     {  
  73.         c=s[now];s[now]=s[now-3];s[now-3]=c;  
  74.         tmp2=dfs(now-3,num+1,1);  
  75.         if(ans)return tmp2;  
  76.         tmp1=min(tmp1,tmp2);  
  77.         c=s[now];s[now]=s[now-3];s[now-3]=c;  
  78.     }  
  79.     return tmp1;  
  80. }  
  81. void IDAStar(int now)  
  82. {  
  83.     sum=len(s);ans=0;  
  84.     while(!ans)  
  85.         sum=dfs(now,0,0);  
  86. }  
  87. int main()  
  88. {  
  89.     int i,j,k,kk,t,x,y,z;  
  90.     while(scanf("%s",s)!=EOF)  
  91.     {  
  92.         if(s[0]=='x')x=0;  
  93.         for(i=1;i<9;i++)  
  94.         {  
  95.             scanf("%s",s+i);  
  96.             if(s[i]=='x')x=i;  
  97.         }  
  98.         if(inverse(s))  
  99.         {  
  100.             printf("unsolvable\n");  
  101.             continue;  
  102.         }  
  103.         IDAStar(x);  
  104.         for(i=1;i<=sum;i++)  
  105.         {  
  106.             if(res[i]==1)printf("u");  
  107.             if(res[i]==2)printf("d");  
  108.             if(res[i]==3)printf("l");  
  109.             if(res[i]==4)printf("r");  
  110.         }  
  111.         printf("\n");  
  112.     }  
  113.     return 0;  
  114. }  


原创粉丝点击