八数码第八境界——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的做法)有了很大的区别。
接下来就仔细讲讲具体细节。
- int dfs(int now,int num,int pos)
- {
- char c;
- int val = len(s);
- if(val+num>sum)
- return val+num;
- res[num]=pos;
int val=len(s)就是求出剩下的曼哈顿距离。
看看这个if语句,如果剩下的曼哈顿距离和当前走出的距离之和大于sum,就剪枝了。返回这个超出搜索距离的距离。
sum是什么呢?就是我们当前的最大搜索距离。
还有int dfs(int now,int num,int pos) 。now是当前的x在数组中哪个位置。num是当前已走出去的步数。pos是当前的操作(上下左右)。
res[num]=pos; 这里就是把操作存进去。当然之前可能有存放过,而且在那个方向失败了,不过这不影响什么。
看一下具体的dfs
- if(pos!=3&&(now+1)%3!=0)
- {
- c=s[now];s[now]=s[now+1];s[now+1]=c;
- tmp2=dfs(now+1,num+1,4);
- if(ans)return tmp2;
- tmp1=min(tmp1,tmp2);
- c=s[now];s[now]=s[now+1];s[now+1]=c;
- }
还有后面一个条件就是如果不在最后一列,那自然可以向右移动。
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的调用方法
- void IDAStar(int now)
- {
- sum=len(s);ans=0;
- while(!ans)
- sum=dfs(now,0,0);
- }
全部代码
- #define N 1123
- char s[10];
- int res[N],sum,ans;
- bool inverse(char ss[])
- {
- int t=0,x,y;
- for(int i=1;i<9;i++)
- for(int j=0;j<i;j++)
- {
- if(ss[j]=='x')continue;
- else x=ss[j]-'0';
- if(ss[i]=='x')continue;
- else y=ss[i]-'0';
- if(x>y)
- t++;
- }
- if(t&1)
- return true;
- return false;
- }
- int len(char str[])
- {
- int ans=0;
- for(int i=0;i<9;i++)
- {
- if(str[i]!='x')
- ans+=abs(i/3-(str[i]-'0'-1)/3)+abs(i%3-((str[i]-'0')-1)%3);
- else
- ans+=(2-i/3)+(2-i%3);
- }
- return ans;
- }
- int dfs(int now,int num,int pos)
- {
- char c;
- int val = len(s);
- if(val+num>sum)
- return val+num;
- res[num]=pos;
- if(val==0)
- {
- ans=1;
- return num;
- }
- int tmp1=INF,tmp2;
- if(pos!=3&&(now+1)%3!=0)
- {
- c=s[now];s[now]=s[now+1];s[now+1]=c;
- tmp2=dfs(now+1,num+1,4);
- if(ans)return tmp2;
- tmp1=min(tmp1,tmp2);
- c=s[now];s[now]=s[now+1];s[now+1]=c;
- }
- if(pos!=4&&now%3!=0)
- {
- c=s[now];s[now]=s[now-1];s[now-1]=c;
- tmp2=dfs(now-1,num+1,3);
- if(ans)return tmp2;
- tmp1=min(tmp1,tmp2);
- c=s[now];s[now]=s[now-1];s[now-1]=c;
- }
- if(pos!=1&&now<6)
- {
- c=s[now];s[now]=s[now+3];s[now+3]=c;
- tmp2=dfs(now+3,num+1,2);
- if(ans)return tmp2;
- tmp1=min(tmp1,tmp2);
- c=s[now];s[now]=s[now+3];s[now+3]=c;
- }
- if(pos!=2&&now>2)
- {
- c=s[now];s[now]=s[now-3];s[now-3]=c;
- tmp2=dfs(now-3,num+1,1);
- if(ans)return tmp2;
- tmp1=min(tmp1,tmp2);
- c=s[now];s[now]=s[now-3];s[now-3]=c;
- }
- return tmp1;
- }
- void IDAStar(int now)
- {
- sum=len(s);ans=0;
- while(!ans)
- sum=dfs(now,0,0);
- }
- int main()
- {
- int i,j,k,kk,t,x,y,z;
- while(scanf("%s",s)!=EOF)
- {
- if(s[0]=='x')x=0;
- for(i=1;i<9;i++)
- {
- scanf("%s",s+i);
- if(s[i]=='x')x=i;
- }
- if(inverse(s))
- {
- printf("unsolvable\n");
- continue;
- }
- IDAStar(x);
- for(i=1;i<=sum;i++)
- {
- if(res[i]==1)printf("u");
- if(res[i]==2)printf("d");
- if(res[i]==3)printf("l");
- if(res[i]==4)printf("r");
- }
- printf("\n");
- }
- return 0;
- }
- 八数码第八境界——IDA*+逆序数判无解
- poj1077八数码问题——境界六(IDA*)
- POJ 1077 Eight(八数码第八境界|IDA*+曼哈顿距离+判断是否有解)
- POJ1077&HDU1043 Eight 八数码第八境界 IDA* hash 康托展开 奇偶剪枝
- 八数码第六境界——双向BFS+康托展开判重+回溯记录路径+逆序数判无解
- 八数码第七境界——A*之曼哈顿+康托展开判重+回溯记录路径+逆序数判无解
- IDA*——Luogu1379 八数码难题
- 菜鸟系列——八数码八境界
- 八数码 八境界
- 八数码八境界
- 八数码 八境界
- 八数码八境界
- poj1077八数码问题——境界二
- hdu1043八数码问题——境界三
- poj1077八数码问题——境界五(A*)
- 八数码的八境界
- 八数码的八境界
- 八数码的八境界
- c++-进制转换
- as 和which 引导定语从句的异同
- text-align:justify真正作用及无效处理方式
- 发送短信验证码+登陆功能
- 基于简单感知器分类算法(matlab实现)
- 八数码第八境界——IDA*+逆序数判无解
- 日志系列之Log4j2异步Loggers
- 前端解决跨域问题的8种方案
- 封装MyFragment
- day 2. 结构体与指针两种引用的方法
- 将ES中的数据推到kafka中,用kylin进行OLAP计算,发现统计数据对不上
- 数据结构——四种最常见的线性表
- which,that 引导定语从句不同
- 常用的sql语句