阅前必读
本博客纯手写,无借鉴,请大胆的提意见哦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)