启发式搜索详解

本文详细介绍了启发式搜索,包括BFS(宽度优先搜索)及其优化版BFS+优先队列,后者对应Dijkstra算法。讨论了Dijkstra算法的原理与实现,并通过堆优化提高效率。此外,文章还探讨了A*搜索算法,强调了估价函数在搜索过程中的重要性,并提供了一个经典的k短路问题作为实例。
摘要由CSDN通过智能技术生成

阅前必读
本博客纯手写,无借鉴,请大胆的提意见哦QwQ

优先队列BFS
回顾普通BFS——BFS+普通队列
BFS是什么
BFS,宽度优先搜索。
它的搜索方式就像涟漪一样,是一层一层遍历下去。具体见下图:

cnt表示遍历的层次。

所谓“涟漪式”的遍历,其实就是以层次的不断向目标状态展开,对图中每一个点的最优值更新,从而达到遍历至目标状态时的最优值。

BFS可以干什么?
一般出现最短路径和最佳方案时可以使用BFS遍历。

BFS+普通队列怎么写?
下面是伪代码:

void BFS(int x)
{
初始化队列Q;
标记x已遍历;
Q.push(x);
while(!Q.empty())
{
int u=Q.top();
Q.pop();
if(u==目标状态)
{
……
}
Q.push(与u相连的未被访问的所有点);
标记u已遍历;
}
}
注:BFS+普通队列对应的是SPFA算法。

学习优化BFS——BFS+优先队列
优化BFS算法采用Dijkstra堆优化的方式求解。
注:BFS+优先队列对应的是Dijkstra算法。

Dijkstra简单回顾
从源点开始向自己的子节点扩展,将已拓展到的子节点对应的边权加入数组d当中,再在数组d当中选取一个最小值,从这个值对应的节点开始继续向下搜索。

值得一提的是,Dijkstra中,d数组里储存的“边权”是相对于源点来说的。
还没有回忆起来?这张图也许能帮到你:

Dijkstra代码简单回顾
void D()
{
for(int i=1;i<=n;i++)
a[i]=inf; //初始化
int k;
a[s]=0; //第一个节点(即根节点)距离根节点(即自己)的距离为0
prt[s]=0; //第一个节点的父亲定义为0
for(int i=1;i<=n;i++)
{
int minn=inf; //找最小边权
for(int j=1;j<=n;j++)
if(!vis[j]) //如果未访问过
if(a[j]<minn) //且此边权小于当前最小边权
{
minn=a[j]; //则更新最小边权
k=j; //记录此节点
}
vis[k]=1; //访问该节点
for(int j=1;j<=n;j++)
if(g[k][j]>0&&!vis[j]) //更新与该节点有连接的点的边权值
if(a[k]+g[k][j]<a[j]) //松弛操作
{
a[j]=a[k]+g[k][j];
prt[j]=k; //记录更新它的值的节点
}
}
}
而在寻找d数组里的最小值时需要O(n)的复杂度,所以我们期望有一种方法可以降低寻找最小值的复杂度。
由于优先队列的最优性质,我们可以用堆优化Dijkstra。

我们怎么用堆优化Dijkstra?
前文提到过堆的用途。所以我们只需要将每次的边权push到堆里,每次取出时就不需要用O(n)的时间来寻找最小值了,直接取堆顶即可。
关于堆,它查询的复杂度是O(1)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值