概念定义
深度优先搜索是选择一个分支,直到尽头才会开始回溯。但在遇到搜索树的每个节点的分支数目非常多,并且答案其实只是在很浅的节点上。那么如果在一开始深搜选错了分支,就很可能在不包含答案的深层子树上浪费大量的时间。
那么此时,我们就可以使用迭代加深的思想,从小到大限制搜索的深度。如果在当前深度限制下搜索不到答案,那么就增加深度,重新进行一次搜索。
虽然理论上重新搜索的代价似乎是挺不必要的,但是随着层数的深入,每层节点数会呈指数性增长。这点重复量和深层子树的规模相比,不值一提。
总之,当搜索树规模随着层次的深入增长很快,并且我们能够确保答案在一个较浅层的节点时,就可以用这个技巧。
题目中的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;
}
}