IDA*算法讲解及例题

引入

考虑这样一个情况:当你在用DFS遍历一棵树找答案。
但是这棵树比较恶心。
在这里插入图片描述
终点虽然说在红色的点,但是一般人的代码先遍历左儿子就会进入左下方那一堆,但是实际上答案离起点很近。

IDDFS

所以,根据上面的情况,我们可以限制一下搜索的深度,超过了深度后就不管了,这样就可以避免无用又浪费时间的搜索。
当我们搜索的对象是一棵树时,找到目标点的时候,此时的深度就是从根节点找到答案的步数。
因此,我们在dfs函数里面加上一个参数 d d d,表示当前搜索的深度,如果其超过了限制深度,就不用管了,直接return。
这就是IDDFS的思想。

IDA*

IDDFS讲完了,那么IDA* 又是什么?
其实就是IDDFS+剪枝。
BFS的A*1是给定准确目标,优化掉不必要的遍历,这和剪枝的思路也是一样的。

例题

P10494 [USACO02FEB] Power Hungry Cows
先考虑暴力的思路,已经得到的数存在一个数组里,然后用当前的指数依次去加,找到答案了就return。
然后是IDDFS的深度限制

for(dep=0;;dep++)if(dfs(1,0))break;

第一个参数是最开始的指数,第二个参数是深度
最后的深度 d e p dep dep就是需要的次数。
接下来考虑剪枝。
对于一个指数 x x x,可以出现的最大情况一定是加上自己变成 2 x 2x 2x,接下来的最大就是变成 4 x 4x 4x 8 x 8x 8x 16 x 16x 16x……
所以,对于指数 x x x,进行 k k k次操作的情况下,最大可以达到 x ⋅ 2 k x\cdot2^k x2k
那么,对于再执行 k k k步的情况下,如果 x ⋅ 2 k x\cdot2^k x2k都没法达到目标,就不必再搜索下去了。
同理,当 x 2 k \frac{x}{2^k} 2kx都大于目标,也没必要再搜索了。

if(x<<(dep-d)<n)return 0;
if(x>>(dep-d)>n)return 0;

return 0意思是不满足条件,继续加深搜索深度。
代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=55;
int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
void print(int x){
	if(x<0)putchar('-'),x=-x;
	if(x<10){putchar(x+'0');return;}
	print(x/10);
	putchar(x%10+'0');
}
int n;
int dep;
int a[N];
bool dfs(int x,int d){
	if(x==n)return 1;//达到目标
	if(d>=dep)return 0;//超过深度
	//剪枝
	if(x<<(dep-d)<n)return 0;
	if(x>>(dep-d)>n)return 0;
	a[d]=x;
	for(int i=d;i>=0;i--){//从大往小遍历,尽量减少搜索次数
		if(dfs(x+a[i],d+1))return 1;
		else if(dfs(x-a[i],d+1))return 1;
	}
	return 0;
}
signed main(){
	n=read();
	for(dep=0;;dep++)if(dfs(1,0))break;
	print(dep);
}

  1. 详见启发式BFS算法讲解及例题
    ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值