IDDFS(迭代加深搜索)精选题and总结
Posted -wallace-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IDDFS(迭代加深搜索)精选题and总结相关的知识,希望对你有一定的参考价值。
引入:什么是IDDFS?
在计算机科学中,迭代深化搜索(iterative deepening search)或者更确切地说迭代深化深度优先搜索 (iterative deepening depth-first search (IDS or IDDFS)) 是一个状态空间(状态图)搜索策略。在这个搜索策略中,一个具有深度限制的深度优先搜索算法会不断重复地运行,并且同时放宽对于搜索深度的限制,直到找到目标状态。IDDFS 与广度优先算法是等价的,但对内存的使用会少很多;在每一步迭代中,它会按深度优先算法中的顺序,遍历搜索树中的节点,但第一次访问节点的累积顺序实际上是广度优先的。
——百度百科
一:一般搜索。
·题目描述:
Luogu P1605 迷宫[原题链接]
·解析:
这一题差不多就是普通DFS的入门题了,适合深搜初学者做。
小技巧:标记和方向数组。
其中标记可以大大减少重复走过的路径,有效地加快搜索效率。
方向数组针对的是这题只要侦测4个方向即可,用一个for循环可以较大的简短代码长度。
其他的,想必大家都了解,此处就不再赘述了。
代码如下:
#include<bits/stdc++.h> using namespace std; int n,m,t; int step[36][36];//记录走过的地方 int maps[6][6];//地图 int sx,sy;//起点 int ex,ey;//终点 int dx[1001],dy[1001];//障碍x、y坐标 int a[5]={0,0,0,-1,1},b[5]={0,-1,1,0,0};//上下左右 int total=0; int check(int mx,int my) { if(mx>=1&&my>=1&&mx<=n&&my<=m) if(maps[mx][my]==0) if(step[mx][my]==0) return 1; return 0; } void search(int x,int y) { if(x==ex&&y==ey) { total++; return; } else { for(int i=1;i<=4;i++) { x+=a[i]; y+=b[i]; if(check(x,y)==1) { step[x][y]=1; search(x,y); step[x][y]=0; x-=a[i]; y-=b[i]; } else { x-=a[i]; y-=b[i]; } } } } int main() { scanf("%d%d%d",&n,&m,&t); scanf("%d%d%d%d",&sx,&sy,&ex,&ey); for(int i=1;i<=t;i++) { scanf("%d%d",&dx[i],&dy[i]); maps[dx[i]][dy[i]]=1; } step[sx][sy]=1; search(sx,sy); printf("%d",total); }
二:迭代加深搜索。
· 题目描述
Luogu P3869 [TJOI2009]宝藏 [原题链接]
· 解析
这一题似乎和上一题不太一样啊——加了一个什么“机关”。
但仔细理解理解,还是蛮好懂的。其实纯粹的DFS是过不了的。
原因:
此题求解最短路径,用穷竭所有情况的DFS大为不利。也许你会说:BFS!这里有一个缺陷,我们知道,BFS需要维护一个队列,以进行“地毯式搜索”。但如果遇到了这种情况……
如图,若右下角的‘@’按下机关,紧接着上面的‘@’进入了,就导致了秩序混乱,产生了错误答案。通俗点讲,就是“森林冰火人”中的常用策略。(此处是个错误)
突然没了思路……
现在,就要使用IDDFS了!
首先,定义一个变量叫maxstep,将DFS函数变成bool形,
那么DFS()的定义就成了:在maxstep步内能否找到答案。再用一个for循环,每次maxstep++。即:
for(maxstep=1;!Dfs(sx,sy,0);maxstep++);maxstep可以控制深度,防止递归到爆栈。
最后只需输出maxstep即可。
另外,我们还发现了有许多情况是搜过许多遍的,所以,在刚刚递归到下一层时,可以先将当前状态Hash一下,存入一个map(Hash值为key,步数为value)中。在这之前,先要判断一下map中是否有更优解,如果有,直接返回;没有,将状态和步数存入map再继续。
每次maxstep++的时候,同时清空map。
代码如下:
#include<bits/stdc++.h> #define hash Do_not_use_hash using namespace std; typedef unsigned long long ull; const int base=1e9+1; map<ull,int> M; int a[31][31]; int n,m,k; int d[11][2]; int t[11][2]; int sx,sy,ex,ey; int maxstep; const int dx[5]= {0,0,0,1,-1},dy[5]= {0,1,-1}; ull hash(int x,int y) { ull temp=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(a[i][j]==0) temp=temp*base+1; else temp=temp*base+2; } temp=temp*base+x; temp=temp*base+y; return temp; } inline int calc(int x,int y) { return abs(ex-x)+abs(ey-y); } bool Dfs(int x,int y,int step) { ull now=hash(x,y); if(M.find(now)!=M.end()&&M[now]<=step) return 0; M[now]=step; if(ex==x&&y==ey) return 1; if(step>=maxstep||step+calc(x,y)>maxstep) return 0; for(int i=1;i<=4;i++) { x+=dx[i],y+=dy[i]; if(x>=1&&y>=1&&x<=n&&y<=m&&!a[x][y]) { for(int h=1;h<=k;h++) if(d[h][0]==x&&d[h][1]==y) a[t[h][0]][t[h][1]]^=1; if(Dfs(x,y,step+1)) { for(int h=1;h<=k;h++) if(d[h][0]==x&&d[h][1]==y) a[t[h][0]][t[h][1]]^=1; x-=dx[i],y-=dy[i]; return 1; } else { for(int h=1;h<=k;h++) if(d[h][0]==x&&d[h][1]==y) a[t[h][0]][t[h][1]]^=1; } } x-=dx[i],y-=dy[i]; } return 0; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { char temp; cin>>temp; if(temp==‘#‘) a[i][j]=1; else a[i][j]=0; if(temp==‘S‘) sx=i,sy=j; if(temp==‘T‘) ex=i,ey=j; } cin>>k; for(int i=1;i<=k;i++) cin>>d[i][0]>>d[i][1]>>t[i][0]>>t[i][1]; for(maxstep=1;!Dfs(sx,sy,0);maxstep++,M.clear()); cout<<maxstep; return 0; }
备注:calc是一个剪枝(即IDA*的体现,以后会提到)。该代码直接提交只有80分,也算是全Luogu第二了。(实在不会优化了,还望指教)
三:总结:
外加几个tips:
IDDfs的前提:一定要有解。
注意DFS是bool型,而不是void型。
IDDFS的优势:
1.时间复杂度只比BFS稍差一点(虽然搜索k+1层时会重复搜索k层,但是整体而言并不比广搜慢很多)。
2.空间复杂度与深搜相同,却比广搜小很多。
3.利于剪枝。
·经典必练
Luogu P2324 [SCOI2005]骑士精神 [原题链接]
以上是关于IDDFS(迭代加深搜索)精选题and总结的主要内容,如果未能解决你的问题,请参考以下文章
C++解题报告 : 迭代加深搜索之 ZOJ 1937 Addition Chains
POJ 3134 - Power Calculus (IDDFS)