技术标签: 算法
BFS 与 DFS 的时间复杂度相同,都是 O ( n + m ) O(n + m) O(n+m),其中 n 表示图的节点数,m 表示图的边数。
当树或者图的所有边的权重都是 1 时,才可以使用 BFS 求最短距离,否则应该使用 DFS 考虑所有情况。
当权重不是 1 的时候,应该使用 Dijkstra 等算法来求最短距离。
队列 —> 先进先出 —> BFS
栈 —> 后进先出 —> DFS
所有的 BFS、DFS 都可以对应一颗树。
bfs 遍历顺序:
bfs 实现遍历主要是依靠 队列 来做。每次取出队头元素,然后再将队头元素的所有子节点加入队尾,一开始将根节点放入空队列中,这样就实现 bfs 遍历了。
通过上图,你会惊奇地发现:队头元素出队的顺序 与 元素加入队列的顺序 竟然一样!
实现 bfs 需要两种数组: 判重数组(定义为布尔数组 st)、队列(用数组实现)。
绝大部分 bfs 都是在节点入队时判重,但是特殊的算法(比如 Dijkstra)会在出队时判重。
没有判重数组的话,bfs 搜索树可能会出现 环,这样就会导致死循环的发生。
对于 队列操作,bfs 框架为:
queue <-- 初始状态
while (queue 非空) {
t <-- 队头元素
for (拓展 t) {
ver <-- 新节点
if (!st[ver]) {
在队尾插入 ver
}
}
}
**迷宫问题是 BFS 最重要的一个问题。我们常常用 BFS 搜索从起点到终点的最短路步长,最短步长就是 BFS 递归的层数。**这是因为 bfs 搜索树的每一层的节点都代表了一种选择,它是按照距离来遍历点的,一开始遍历距离为 1 的点,再从距离为 1 的点开始,遍历离起点 距离 为 2 的点,以此类推…… 因此从起点到终点的最小层数就是短步长。
比如这个迷宫的 bfs 搜索树(S 表示起点,E 表示终点)
错误代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
const int N = 100010, M = 2 * N;
int n, m;
int h[N], e[M], ne[M], idx;
bool st[N];
int d[N]; // d[i]存储从1号点到i号店的最短路径,可以将 d 数组初始化为 -1,表示当前节点还没有被遍历过。
//! 注意,对于树来说,你可以使用布尔数组st[i]来表示当前节点是否已经被遍历过。这是因为在树结构中,i号节点只可能被它的父节点遍历
//! 注意,对于图来说,你不能用一个布尔数组st[i]来表示当前节点是否已经被遍历过。这是因为在图结构中,可能有多个节点指向i号节点
void init() {
memset(h, -1, sizeof h);
memset(d, -1, sizeof d);
}
void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void bfs() {
queue<int> q;
q.push(1);
// st[1] = true;
while(q.size()) {
int now = q.front();
q.pop();
if (!st[now]) {
st[now] = true;
for (int i = h[now]; ~i; i = ne[i]) {
int j = e[i];
q.push(j);
d[j] = d[now] + 1;
if (j == n) return;
}
}
}
}
int main()
{
init();
scanf("%d%d", &n, &m);
int a, b;
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &a, &b);
add(a, b);
}
bfs();
printf("%d\n", d[n]);
}
正确代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
const int N = 100010, M = 2 * N;
int n, m;
int h[N], e[M], ne[M], idx;
bool st[N];
int d[N]; // d[i]存储从1号点到i号店的最短路径,可以将 d 数组初始化为 -1,表示当前节点还没有被遍历过。
//! 注意,对于树来说,你可以使用布尔数组st[i]来表示当前节点是否已经被遍历过。这是因为在树结构中,i号节点只可能被它的父节点遍历
//! 注意,对于图来说,你不能用一个布尔数组st[i]来表示当前节点是否已经被遍历过。这是因为在图结构中,可能有多个节点指向i号节点
void init() {
memset(h, -1, sizeof h);
memset(d, -1, sizeof d);
}
void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void bfs() {
queue<int> q;
q.push(1);
// st[1] = true;
d[1] = 0; //* 这一步初始化容易忘记
while(q.size()) {
int now = q.front();
q.pop();
for (int i = h[now]; ~i; i = ne[i]) {
int j = e[i];
if (d[j] == -1) {
q.push(j);
d[j] = d[now] + 1;
if (j == n) return;
}
}
}
}
int main()
{
init();
scanf("%d%d", &n, &m);
int a, b;
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &a, &b);
add(a, b);
}
bfs();
printf("%d\n", d[n]);
}
文章浏览阅读3.5k次。作者:郑晓,龙欣,弹性计算异构计算项目组让各位久等了,阿里小二这就开始上新菜:“GPU分片虚拟化”。对于“分片”的理解,相信大家已经不陌生了。此处的分片从两个维度上来定义:其一,是对GPU在时间片段上的划分,与CPU的进程调度类似,一个物理GPU的计算engine在几个vGPU之间共享,而调度时间片一般都在1ms-10ms左右,其二,是对GPU资源的..._vgpu可以分配全部显存吗
文章浏览阅读1.8w次,点赞7次,收藏41次。目录一,vue-cli2的安装和项目创建(一)安装vue-cli2(二)创建vue-cli2项目二, vue-cli3的安装和项目创建(一)vue-cli3的安装(二)vue-cli3项目创建1,用dos命令的方式2,图形化界面的方式一,vue-cli2的安装和项目创建(一)安装vue-cli2在安装vue-cli2之前,先要安装cnpm,参...
文章浏览阅读261次。【代码】LLM-项目详解(一):Chinese-LLaMA-Alpaca【modeling_llama.py文件】_transformers modeling_llama.py
文章浏览阅读939次,点赞18次,收藏17次。博主双非一战物理跨考上岸了华科软件,初复试排名均是22/55。专业课408分数是126分,来浅谈一下我的经验。
文章浏览阅读3.7k次,点赞13次,收藏84次。本文将会介绍 AJAX 的原理和使用方法,并帮助你在短时间内掌握这一重要的前端技术。我们将从 AJAX 的基本概念入手,深入探讨 AJAX 的核心技术——XMLHttpRequest 对象以及常用的数据交互方式。通过本文的学习,你将能够轻松地了解 AJAX 的工作方式和应用场景,从而为你的 Web 应用程序添加更多的交互性和实时性。_ajax学习教程
文章浏览阅读838次。源码#include <iostream>#include <pcl\io\pcd_io.h>#include <pcl/point_cloud.h>#include <pcl/visualization/pcl_visualizer.h>#include <pcl/io/io.h>#include <pcl/keypoints/harris_3D.h>//harris特征点估计类头文件声明#include <cst_点云 harris角点检测 r_normal r_keypoint
文章浏览阅读309次。自 黑马程序员。_前端页面的认识
文章浏览阅读5.3k次。目录使用背景和场景pod亲和性和反亲和性的区别podAntiAffinity实战部署反亲和性分软性要求和硬性要求附完整的deployment.yaml配置注意使用背景和场景业务中的某个关键服务,配置了多个replica,结果在部署时,发现多个相同的副本同时部署在同一个主机上,结果主机故障时,所有副本同时漂移了,导致服务间断性中断基于以上背景,实现一个服务的多个副本分散到不同的主机上,使每个主机有且只能运行服务的一个副本,这里用到的是Pod anti-affinit_podantiaffinity
文章浏览阅读228次。参加完发布会刚到家,先占个坑,等我吃饱了再来回答。~~~~~~~~~~~~~~~~~~~~小爱mini已开箱,电源改成usb接口了,5V2A。扬声器在音箱底部,顶部的麦克风只有4个。灯光放到了中间,而且灯光颜色,光斑大小会变化。按键做得比较烂,mini版省钱省在这上面了。小爱同学中间有个play键,可以迅速按一下停止或开始播放,但是mini版似乎把这个按键给精减了。其它几个按键按下之后反应比较慢,..._python控制小爱音箱
文章浏览阅读7.7k次,点赞17次,收藏77次。插入排序属于稳定排序法,是一种常用的排序算法。直接插入排序算法可以利用静态数组来实现,也可以使用静态链表或者单链表来实现。本文给出了直接插入算法的单链表实现方法。_单链表插入排序
文章浏览阅读5.6k次,点赞21次,收藏127次。从0到服务器开发——TinyWebServer前言:修改、完整注释、添加功能的项目代码:https://github.com/white0dew/WebServer它是个什么项目?——Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器。使用 线程池 + 非阻塞socket + epoll(ET和LT均实现) + 事件处理(Reactor和模拟Proactor均实现) 的并发模型 使用状态机解析HTTP请求报文,支持解析GET和POST请求 访问服务_tinywebserver c++
文章浏览阅读1.2w次,点赞14次,收藏23次。笔者软件环境: eclipse neno; jdk1.8.0_101; maven 3.3.9安装maven之后,在eclipse中新建maven project时: 看到的画面与教程不一样: 根本找不到archetype的模板;选择catalog,根本没反应;这样子进行不下去啊,宝宝好慌啊;百度google齐上阵,为_select an archetype空白