启发式搜索--A*、IDA*算法详解

A*大意:利用一个估价函数h()确定点的遍历和更新顺序从而减少遍历次数
IDA*大意:通过贪心取答案步数,并用于与估价函数剪枝,逐步验证得出正确答案。

可能看起来有点迷,其实并不难,下面将用谁都不懂通俗易懂的方式讲解。
特点是都常用于骗分。


前置芝士:最短路和深搜

相信大家都会。


算法:

1. A*

感觉并不是很需要图啊。。。

设起点到终点的总费用为f(n),从起点到当前点的已知费用为g(n),预估当前点到终点的费用为h(n)。
显然我们可以预估f(n)=g(n)+h(n),便得到了一个总费用的近似值(先不考虑正确性)。

得到近似值之后,便可以加入一个小根的优先队列。明显总费用越小越好,所以先遍历预估总费用小的点。
第k次到达终点,便是k短路。
代码表示:(c++演示

struct data{
   
	int g,h;
	bool operator <(const data &v)const{
   
		return g+h>v.g+v.h;
	} 
}
priority_queue<data>q;

注意到当前点到终点的费用是预估而不是精确值,与广搜等遍历找最小算法不同,它体现了启发性,所以是启发式搜索。

该算法保证正确性的条件是h(n)<=h*(n),其中h*(n)为当前点到终点的确定的最小费用,h(n)>=0。

证明:它的最优性质体现在当到达终点时,h(n)<=h*(n)=0,那么h(n)=0,f(n)=g(n)+h(n)=g(n)+0=f*(n),其中f*(n)为真正的总费用,即f(n)就为最短路径。
(参考:https://bbs.csdn.net/topics/70416815)

其中当h(n)越靠近h*(n),效率越优秀。这一点可以感性理解,越靠近真实值就越准确(证明可以买专业书看
所以A*算法的运行效率取决于估价函数的优劣。

同样的,A*也可以用于求k短路问题。
因为高效率,我们可以一直跑,直到第k次到达终点,即为k短路。

当然,我们既然能够跑多次,那么跑一次最短路绰绰有余。我们不如从终点往回用dijkstra等算法得到终点到每个点的距离,即每个点的h*(n),此时估价函数与实际距离相同,必然最优。

2. IDA*

这是另外一种方向,但仍要用到上面所说的f(n),g(n),和h(n)。

我们不再直接得到费用,而是采取贪心的方法预设一个总费用,并验证是否可行,不可行就增大这个费用,重复操作,直到找到一个可行的费用为止,该费用就是答案(十分暴力

有了这个总费用,相当于给你的算法加了一个天花板,限制了天马行空的枚举。
用代码的形式写出来就是:

if(g(n)+h(n)>f(n)) return;

但别小看这一句,它能大大优化爆搜,使复杂度变得玄学而通过。
h(n)一般每个状态都计算一遍或者从上一个状态转移。

常用于数据量在两位数以内的爆搜题。


技巧:

在求k短路时,可以设置一个数组限制每个点只能到达k次,因为已经是到点x的k短路了,再从x走到终点必然最优也是k短路,所以每个点到达k次以上没有意义,可以剪枝。


代码:

1. A* 洛谷 P4467 [SCOI2007]k短路

没有办法,出题人又卡A*。。。

#include<bits/stdc++.h>
using namespace std;
int e1[10010],w1[10010],nxt1[10010],head1[110],cnt1;
int e2[10010],w2[10010],nxt2[10010],head2[110],cnt2;
int dis[110],n,m,k,a,b;
bool vis[110];
struct data1{
   
	int x,s;
	bool operator <(const data1&v)const{
   
		return s>v.s;
	}
};
priority_queue<data1>q1;
struct data2{
   
	int x,s;
	long long sta;
	vector<int>v;
	bool operator <(const data2&y)const{
   
		if(s+dis[x]!=y.s+dis[y.x])
		return s+dis[x]>y.s+dis[y.x];
		for(int i=0;i<min(v.size(),y.v.size());i++)
		if(v[i]!=y.v[i]) return</
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
A*算法IDA*算法都是启发式搜索算法,它们都是用于解决最短路径问题的常用算法。其中,A*算法在搜索时利用了启发式函数来估计从当前节点到目标节点的距离,从而选择最优的节点进行搜索。而IDA*算法则是在A*算法基础上出的改进,其主要区别是不使用任何额外的内存空间,而是将估价函数的值作为深度限制,直到找到目标节点或者超过深度限制为止。 具体来说,A*算法维护一个open列表和一个closed列表。open列表中保存了待搜索的节点,closed列表中保存已经被搜索过的节点。每次从open列表中选择一个f值最小的节点进行扩展,并将其加入closed列表中。扩展时,对于当前节点的每个子节点计算估价函数值f(n)=g(n)+h(n),其中g(n)是从起点到当前节点的实际代价,h(n)是从当前节点到目标节点的估计代价。这样,每次选择f值最小的节点进行扩展时,就能够尽可能地朝着目标节点前进。 IDA*算法则是将A*算法中的open列表替换成一个栈,在搜索时将当前搜索深度作为阈值,不断更新阈值来限制搜索深度。具体来说,每次从起点开始,将阈值设置为起点到目标节点的估价函数值,然后进行深度优先搜索。如果搜索到某个节点的f(n)>threshold,则将其返回,并将阈值更新为f(n)。这样,IDA*算法通过不断增加深度限制来逐步逼近最短路径,直到找到目标节点或者搜索到达最大深度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值