update
2021/8/1 补充了部分内容
2020/11/27 更新了关于优先队列的文章链接
基本概念
图
图是一种数据结构,定义为graph=(V,E)。V是一个非空有限集合,代表顶点(结点),E代表边的集合。 – 来自《信息学奥赛一本通》
(真.生涩难懂 )
队列(先进后出表(FLFO))
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。 --来自百度百科
广度优先算法(BFS)
定义
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。 ——来自百度百科
实现原理(图论)
只想知道bfs对于迷宫问题是如何实现的可以略过这里~
- 要实现bfs,需要借助一个队列来实现。
用几张图片来解释一下
初始化,队列空空。
首先,将节点一入队。
接下来,取出指针指向的节点1,寻找与它相邻的结点2,3并入队。
然后,依次取出节点2,3,寻找他们的可扩展的结点。2与4相邻,3与5、6相邻。依次将4,5,6入队。
接着,依次取出结点4,5,6。4无可扩展结点,5有可扩展结点7,6无可扩展结点。将7入队。
最后,取出7,无结点可扩展,bfs结束。
bfs对于图的遍历,大概就是这个样子。
实现原理(迷宫问题)
接下来我们画图来解析一下bfs走迷宫的过程:、
我们以(1,1)为起点,以(5,5)为终点,并规定向右为 x x x 轴正方向,向下为 y y y 轴正方向。
蓝色表示正在被搜索到的点,红色表示正在以该点为起点搜索,黄色表示已经被搜索的点。
同样的,还是需要借助队列来实现
首先, 将 ( 1 , 1 ) (1,1) (1,1)入队
然后,以(1,1)为起始点,开始搜索,并将符合条件的界结点入队。
接下来,分别以以(1,2)、(2,2)、(2,1)为起点扩展,并将满足条件的结点入队。
以(1,3)、(3,2)、(3,3)、(2,3)、(3,1)为起点向外扩展,并将满足条件的结点入队。
以(1,4)、(2,4)、(3,4)、(4,4)、(4,3)、(4,2)、(4,1)为起点向外扩展,并将满足条件的结点入队。
在队列中找到了目标点(5,5),完成搜索。
这就是bfs在迷宫问题的实现过程。
算法特点
由上可以观察出,bfs算法的特点是先寻找一层中的所有结点,然后一层一层的向下推,直到找到正确的结果为止。bfs算法的这个特点决定了它的一个功能——寻找最短路径。在图论中,Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。
基本框架
void bfs()
{
while(!q.empty()) //当队列不为空时
{
int t=q.front();//
q.pop();//
if(该节点为目标条件){
}
for(int i=1;i<=n;++i){
if(新结点满足条件&&新结点未被重复搜索){
int tt;
vis[tt]=1//标记该节点
q.push(tt); //存入新的结点
}
}
}
}
光看没有用,得来几道题练练手。
例题
题目传送门&题解
NOI 2971:抓住那头牛http://noi.openjudge.cn/ch0205/2971/
题解:https://blog.csdn.net/qq_54173335/article/details/118446400
NOI 7218:献给阿尔吉侬的花束http://noi.openjudge.cn/ch0205/7218/
题解:https://blog.csdn.net/qq_54173335/article/details/118444562
洛谷P1332 血色先锋队https://www.luogu.com.cn/problem/P1332
题解:https://blog.csdn.net/qq_54173335/article/details/118486723
题解都是我自己写的。
写在最后
这篇文章只讨论了简单的bfs问题,实际上,bfs只是平时解题的一种偏向暴力的手段,在题目中很少会只涉及bfs,还可能涉及图的遍历之类等问题。大家可以去亲自尝试一下其他可以使用bfs的题目,这样对bfs算法的应用也就更加熟练。
有空的话,我会再更新一个关于优先队列与bfs的问题。 已经写完了
欢迎各位dalao们对本文批评指正