搜索—迭代加深
概念定义
深度优先搜索是选择一个分支,直到尽头才会开始回溯。但在遇到搜索树的每个节点的分支数目非常多,并且答案其实只是在很浅的节点上。那么如果在一开始深搜选错了分支,就很可能在不包含答案的深层子树上浪费大量的时间。
那么此时,我们就可以使用迭代加深的思想,从小到大限制搜索的深度。如果在当前深度限制下搜索不到答案,那么就增加深度,重新进行一次搜索。
虽然理论上重新搜索的代价似乎是挺不必要的,但是随着层数的深入,每层节点数会呈指数性增长。这点重复量和深层子树的规模相比,不值一提。
总之,当搜索树规模随着层次的深入增长很快,并且我们能够确保答案在一个较浅层的节点时,就可以用这个技巧。
题目中的ShowTime
Addition chains (POJ 2248)
这道题,是搜索枚举题。在最坏的情况下深度可以达到100。但由于题目仅仅要求一个短序列的可行解,那么就算从1开始枚举,深度也绝不会超过30层(口胡)。这就符合迭代加深的思想,即答案一定在浅层里。
那么这道题需要一个数组path来存储当前确定好的序列是什么
并加入如下剪枝优化:
1.path[0—u-1],从大到小枚举。这样可以更快的接近n,以达到序列最短的目的。
2.判重。对于某两组不同的数,其相加之和可能相同。申请一个bool数组来判重。如果该数已经被搜索过,则直接跳过搜索。
#include<iostream> #include<algorithm> using namespace std; const int N=110; int path[N]; int n; bool dfs(int u,int depth){ if(u==depth){ return path[u-1]==n; } bool pc[N]={false}; for(int i=u-1;i>=0;i--){ for(int j=i;j>=0;j--){ int s=path[i]+path[j]; if(s>=path[u-1]&&s<=n&&!pc[s]){ pc[s]=true; path[u]=s; if(dfs(u+1,depth)) return true; } } } } int main(){ while(cin>>n,n){ int depth=1; path[0]=1; while(!dfs(1,depth))depth++; for(int i=0;i<depth;i++){ cout<<path[i]<<" "; } cout<<endl; } }