搜索—迭代加深

概念定义

深度优先搜索是选择一个分支,直到尽头才会开始回溯。但在遇到搜索树的每个节点的分支数目非常多,并且答案其实只是在很浅的节点上。那么如果在一开始深搜选错了分支,就很可能在不包含答案的深层子树上浪费大量的时间。

那么此时,我们就可以使用迭代加深的思想,从小到大限制搜索的深度。如果在当前深度限制下搜索不到答案,那么就增加深度,重新进行一次搜索。

虽然理论上重新搜索的代价似乎是挺不必要的,但是随着层数的深入,每层节点数会呈指数性增长。这点重复量和深层子树的规模相比,不值一提。

总之,当搜索树规模随着层次的深入增长很快,并且我们能够确保答案在一个较浅层的节点时,就可以用这个技巧。

题目中的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;
    }
} 
原文地址:https://www.cnblogs.com/Uninstalllingyi/p/11284994.html