迭代加深搜索IDDFS
Obito
·
·
个人记录
1.问题引入
搜索是我们日常代码中常用的一个算法,众所周知搜索分为深搜(DFS)和广搜(BFS),两种方法的适用性很广也各有优缺点,是做题 (骗分) 是不可多得的一个好方法,下面来做一个简单分析:
1.1 DFS:
优势:一条路走下去,可以适用于多个方面
劣势:有时时间太慢,不够优秀
1.2 BFS:
优势:一层一层扩展,先找到的解一定是最优解
劣势:用到队列扩展时可能会爆空间
所以,两种算法都有自己的缺点,那我们可不可以把它均衡一下呢?IDDFS就因此而生
2.算法分析:
2.1:算法思路
1.在我们确定了搜索树后,我们规定一个深度
2.我们从根节点开始,一次搜索一层,如果搜索深度等于层数仍未找到答案,深度加1.否则此层为最小答案。
3.循环之前步骤
2.2优劣势:
2.2.1优势:
1. 不会因为搜索太深而像dfs一样超时。
2. 没有队列储存扩展的状态,而像bfs一样超空间。
2.2.2劣势:
1.重复,容易超时
2.3.适合问题
1.从题目中直接或间接的知道答案的深浅
2.搜索树要随着深度增加,结点数快速增加
3.典型例题:
3.1加成序列
3.1.1 题目分析:
1.搜索解此题似乎都可以看得出来。
2.用迭代加深的原因:从样例我们可以看到当N=77时也只有9层,又N小于100,所以我们不难发现层数并不深。而节点数是快速增加的,具体看代码。
3.1.2:代码
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
inline void write(int X)
{
if(X<0) {X=~(X-1); putchar('-');}
if(X>9) write(X/10);
putchar(X%10+'0');
}
const int maxn=100+10;
int now[maxn],dep,n,s;//now表示记录答案的数组,dep深度。
bool dfs(int cur){//cur当前层数
if(cur==dep)return now[cur]==n;//如果到了当前层数,且最后一个为所求即可返回
bool vis[maxn]={false};
for(int i=cur;i>=1;i--){
for(int j=i;j>=1;j--){
int nxt=now[i]+now[j];//下一个数必须有前面的数得到
if(nxt<=n&&nxt>now[cur]){//下一个数的范围
now[cur+1]=nxt;//记录下一个数
if(dfs(cur+1)==true)return true;//搜索
else vis[nxt]=1;
}
}
}
return false;
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
while(1){//多组数据
n=read();
if(n==0)break;
dep=1;//最少一个数,也就是一层
now[1]=1;//第一个数肯定是一
while(dfs(1)==0)dep++;//如果没找到答案层数加一
for(int i=1;i<=dep;i++)cout<<now[i]<<" ";//输出
cout<<endl;
}
return 0;//完结散花
}
3.1.2问题总结:如果按照这个方法写肯定过不去,会出现超时的情况,所以我们该怎么办呢?
3.1.3 剪枝:
剪枝便是大家都会想到的方法,那我们来回顾一下剪枝的类型
3.1.3.1 最优性剪枝:如果当前值已大于现求出的最小答案,就不用再继续搜索了,而IDDFS先搜到的一定是最优答案,所以用不了最优性剪枝
3.1.3.2 去重剪枝:如果出现了重复,可以不用把这个点丢进搜索树,所以这个剪枝是可以用的,我们可以用一个vis数组来记录当前数字有没出现过,可以有效节省时间
3.1.3.3 可行性剪枝:如果根本就不可行就不需要继续搜下去了,我们不难发现当前最大值最多以每次翻二倍逼近答案,所以如果当前最大值乘上2的剩余层数的次方仍然无法逼近的话,就可以剪去。
结尾:剪枝可以留给各位读者自行思考,如有困难或对我内容的更正可以私信我