BFS-程序员宅基地

技术标签: 算法  

BFS

BFS 与 DFS 的时间复杂度相同,都是 O ( n + m ) O(n + m) O(n+m),其中 n 表示图的节点数,m 表示图的边数。

当树或者图的所有边的权重都是 1 时,才可以使用 BFS 求最短距离,否则应该使用 DFS 考虑所有情况。

当权重不是 1 的时候,应该使用 Dijkstra 等算法来求最短距离。

BFS 原理

队列 —> 先进先出 —> BFS

栈 —> 后进先出 —> DFS

所有的 BFS、DFS 都可以对应一颗树。

bfs 遍历顺序:image-20201014201015283

bfs 实现遍历主要是依靠 队列 来做。每次取出队头元素,然后再将队头元素的所有子节点加入队尾,一开始将根节点放入空队列中,这样就实现 bfs 遍历了。

image-20201014201617028

通过上图,你会惊奇地发现:队头元素出队的顺序 与 元素加入队列的顺序 竟然一样!

BFS 代码

实现 bfs 需要两种数组: 判重数组(定义为布尔数组 st)队列(用数组实现)

绝大部分 bfs 都是在节点入队时判重,但是特殊的算法(比如 Dijkstra)会在出队时判重。

为什么需要判重数组?

没有判重数组的话,bfs 搜索树可能会出现 ,这样就会导致死循环的发生。

队列在 BFS 中的操作

对于 队列操作,bfs 框架为:

queue <-- 初始状态
while (queue 非空) {
    
	t <-- 队头元素
   for (拓展 t) {
    
       ver <-- 新节点
       if (!st[ver]) {
    
           在队尾插入 ver
       }
   }
}

BFS 解决的问题

**迷宫问题是 BFS 最重要的一个问题。我们常常用 BFS 搜索从起点到终点的最短路步长,最短步长就是 BFS 递归的层数。**这是因为 bfs 搜索树的每一层的节点都代表了一种选择,它是按照距离来遍历点的,一开始遍历距离为 1 的点,再从距离为 1 的点开始,遍历离起点 距离 为 2 的点,以此类推…… 因此从起点到终点的最小层数就是短步长。

比如这个迷宫的 bfs 搜索树(S 表示起点,E 表示终点)

image-20201014204537343

树与图的 BFS

image-20201119162614003

错误

利用 BFS 求从节点 1 到节点 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;

    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]);
}

AcWing

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_44960253/article/details/110245727

智能推荐

浅谈GPU虚拟化技术(四)- GPU分片虚拟化-程序员宅基地

文章浏览阅读3.5k次。作者:郑晓,龙欣,弹性计算异构计算项目组让各位久等了,阿里小二这就开始上新菜:“GPU分片虚拟化”。对于“分片”的理解,相信大家已经不陌生了。此处的分片从两个维度上来定义:其一,是对GPU在时间片段上的划分,与CPU的进程调度类似,一个物理GPU的计算engine在几个vGPU之间共享,而调度时间片一般都在1ms-10ms左右,其二,是对GPU资源的..._vgpu可以分配全部显存吗

vue-cli3的安装和项目创建-程序员宅基地

文章浏览阅读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,参...

LLM-项目详解(一):Chinese-LLaMA-Alpaca【transformers/models/llama/modeling_llama.py文件】_transformers modeling_llama.py-程序员宅基地

文章浏览阅读261次。【代码】LLM-项目详解(一):Chinese-LLaMA-Alpaca【modeling_llama.py文件】_transformers modeling_llama.py

408经验贴-程序员宅基地

文章浏览阅读939次,点赞18次,收藏17次。博主双非一战物理跨考上岸了华科软件,初复试排名均是22/55。专业课408分数是126分,来浅谈一下我的经验。

从零开始学习 AJAX:超详细!15 分钟搞定 AJAX 原理和使用方法_ajax学习教程-程序员宅基地

文章浏览阅读3.7k次,点赞13次,收藏84次。本文将会介绍 AJAX 的原理和使用方法,并帮助你在短时间内掌握这一重要的前端技术。我们将从 AJAX 的基本概念入手,深入探讨 AJAX 的核心技术——XMLHttpRequest 对象以及常用的数据交互方式。通过本文的学习,你将能够轻松地了解 AJAX 的工作方式和应用场景,从而为你的 Web 应用程序添加更多的交互性和实时性。_ajax学习教程

PCL学习笔记(27)——Harris角点检测_点云 harris角点检测 r_normal r_keypoint-程序员宅基地

文章浏览阅读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

随便推点

前端——基础认知(1)_前端页面的认识-程序员宅基地

文章浏览阅读309次。自 黑马程序员。_前端页面的认识

实战指定pod分散部署节点之pod反亲和性(podAntiAffinity)-程序员宅基地

文章浏览阅读5.3k次。目录使用背景和场景pod亲和性和反亲和性的区别podAntiAffinity实战部署反亲和性分软性要求和硬性要求附完整的deployment.yaml配置注意使用背景和场景业务中的某个关键服务,配置了多个replica,结果在部署时,发现多个相同的副本同时部署在同一个主机上,结果主机故障时,所有副本同时漂移了,导致服务间断性中断基于以上背景,实现一个服务的多个副本分散到不同的主机上,使每个主机有且只能运行服务的一个副本,这里用到的是Pod anti-affinit_podantiaffinity

python和小爱同学_小爱mini与小爱同学除了外观,还有什么较大的区别?-程序员宅基地

文章浏览阅读228次。参加完发布会刚到家,先占个坑,等我吃饱了再来回答。~~~~~~~~~~~~~~~~~~~~小爱mini已开箱,电源改成usb接口了,5V2A。扬声器在音箱底部,顶部的麦克风只有4个。灯光放到了中间,而且灯光颜色,光斑大小会变化。按键做得比较烂,mini版省钱省在这上面了。小爱同学中间有个play键,可以迅速按一下停止或开始播放,但是mini版似乎把这个按键给精减了。其它几个按键按下之后反应比较慢,..._python控制小爱音箱

基于单链表实现直接插入排序算法详解_单链表插入排序-程序员宅基地

文章浏览阅读7.7k次,点赞17次,收藏77次。插入排序属于稳定排序法,是一种常用的排序算法。直接插入排序算法可以利用静态数组来实现,也可以使用静态链表或者单链表来实现。本文给出了直接插入算法的单链表实现方法。_单链表插入排序

从零开始实现TinyWebServer_tinywebserver c++-程序员宅基地

文章浏览阅读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++

select an archetype 空白--eclipse新建maven项目的bug_select an archetype空白-程序员宅基地

文章浏览阅读1.2w次,点赞14次,收藏23次。笔者软件环境: eclipse neno; jdk1.8.0_101; maven 3.3.9安装maven之后,在eclipse中新建maven project时: 看到的画面与教程不一样: 根本找不到archetype的模板;选择catalog,根本没反应;这样子进行不下去啊,宝宝好慌啊;百度google齐上阵,为_select an archetype空白