惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
D
Docker
S
SegmentFault 最新的问题
博客园 - 聂微东
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
GbyAI
GbyAI
L
LangChain Blog
Vercel News
Vercel News
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
T
Threat Research - Cisco Blogs
T
Threatpost
Scott Helme
Scott Helme
T
Tailwind CSS Blog
Latest news
Latest news
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
The Register - Security
The Register - Security
罗磊的独立博客
P
Proofpoint News Feed
腾讯CDC
S
Schneier on Security
雷峰网
雷峰网
A
About on SuperTechFans
T
Tenable Blog
F
Full Disclosure
Cyberwarzone
Cyberwarzone
博客园_首页
有赞技术团队
有赞技术团队
K
Kaspersky official blog

文章列表

5月月考 - faryou的博客 - 日记 faryou的博客-五一回老家 【汇编 - 功能】中断安装中断实现 【汇编&硬件】时钟中断的具体实现 faryou的博客-这些年,我不再看《熊出没》 【汇编&硬件】关机中断的具体实现 【汇编&硬件】网络连接相关中断的具体实现 faryou的博客-年初小记 【汇编&硬件】鼠标控制中断的具体实现 【汇编&硬件】声音输出中断的具体实现 【汇编&硬件】屏幕输出中断的具体实现 【汇编&硬件】磁盘读取中断的具体实现 【汇编&硬件】键盘读取中断的具体实现 【汇编】汇编环境的搭建及Debug的使用教程 【汇编】漫谈:学习汇编后的一些思考 faryou的博客-关于本站即日起实行“一站三体”运营制度 【汇编基础教程】完结篇 写在最后:前言 【汇编基础教程】使用BIOS的中断实现键盘输入及磁盘I/O 【汇编基础教程】中断 【汇编基础教程】端口 【汇编基础教程】标志寄存器 【汇编基础教程】寄存器和内存&一些基本命令的说明 【汇编基础教程】来存一些数据! 【汇编基础教程】段 【汇编基础教程】再谈栈 【汇编基础教程】更灵活的定位内存 【汇编基础教程】来写个“函数” 【汇编基础教程】理解一下[bx]和loop指令 【汇编基础教程】跳一跳! faryou的博客-我的竞赛经历&对人生的一些思考 faryou的博客-关于现在中小学计算机课的一些想法及思考 faryou的博客-2025年度总结 faryou的博客-临平山下十五年 faryou的博客-Windows 10即将停止支持,谈谈自己从小到大用电脑的感受 faryou的博客-谈谈一名10后的怀旧情怀 【汇编基础教程】8086CPU工作原理 【C语言】指针的理解与应用 【算法教程】【C/C++】DP(动态规划):区间DP——程序设计思路与代码实现 【算法教程】【C/C++】DFS(深度优先搜索)——程序设计思路与代码实现 【算法教程】【C/C++】单源最短路径——程序设计思路与代码实现 【算法教程】【C/C++】最小生成树——程序设计思路与代码实现 【算法教程】【C/C++】并查集——程序设计思路与代码实现 【算法教程】【C/C++】DP(动态规划):背包DP——程序设计思路与代码实现 【算法教程】【C/C++】DP(动态规划):简单动规问题——程序设计思路与代码实现 【算法教程】【C/C++】递推——程序设计思路与代码实现 【算法教程】【C/C++】三分算法——程序设计思路与代码实现 【算法教程】【C/C++】二分答案——程序设计思路与代码实现 【算法教程】【C/C++】二分查找——程序设计思路与代码实现 【算法教程】【C/C++】贪心算法——程序设计思路与代码实现 【算法教程】【C/C++】基础数学:快排——程序设计思路与代码实现 【算法教程】【C/C++】基础数学:快速幂——程序设计思路与代码实现 【算法教程】【C/C++】基础数学:进制转换——程序设计思路与代码实现 一文弄懂C++中的自定义函数
【算法教程】【C/C++】BFS(广度优先搜索)——程序设计思路与代码实现
faryou · 2025-02-01 · via

前言
广度优先搜索适合用于解决一些走迷宫之类的问题,可以解决深度优先搜索“搜得太深一时出不来”的问题。今天我们学习一下BFS的基本思路。

程序设计思路
BFS与DFS不同就在于BFS是按照层次遍历(在树上表现为从上到下一层一层,横向遍历),而DFS则是有多深走多深,不管层数。理论上来说,两者都属于暴力。
BFS通过队列实现,即每次从队列中取出一个点进行相关操作,并在这次循环内察看其子节点是不是叶子节点,如果是非叶子节点就把这个点入队,之后将这个父节点出队,处理下一个点,直到处理完所有节点(队列空),实现遍历。
还是下面这棵树:
202408311725079771374628.png
使用BFS的遍历顺序为:2→7→8→1→6→9→5→3→4。

代码实现
来看一道题:
202408311725083121921990.png
这是一道经典的BFS题目,我们可以将马不同的行走路线看成一棵树上不同的分支。直接上代码——

#include <bits/stdc++.h>
using namespace std;

int n,m,x,y,ans[401][401],ssb[9]={0,-2,-2,-1,-1,2,2,1,1},sbb[9]={0,-1,1,-2,2,-1,1,-2,2},iq,aq;//n、m、x、y如题意,ans存放从起点到各个点的最短路径,iq、aq为临时变量
bool visit[401][401];//记录当前点有没有访问过

int main(){
    queue<int> f1,f2;//队列,分别记录f1与f2
    scanf("%d%d%d%d",&n,&m,&x,&y);
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans[i][j]=-1;
    f1.push(x);
    f2.push(y);//先将起点入队,开始计算
    ans[x][y]=0;//起点到起点距离为0
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) visit[i][j]=false;//初始化
    visit[x][y]=true;//已经访问过起点
    while(!f1.empty()){//循环直到队列空
        iq=f1.front();
        aq=f2.front();//取出x、y分别计算
        f1.pop();
        f2.pop();//出队
        for(int i=1;i<=8;i++){//马下一步可以到八个方向
            int nexx=iq+ssb[i];
            int nexy=aq+sbb[i];//临时变量记录
            if(nexx>0 && nexy>0 && nexx<=n && nexy<=m && !visit[nexx][nexy]){//判断是否超界或访问过
                visit[nexx][nexy]=true;//当前点标记
                ans[nexx][nexy]=ans[iq][aq]+1;
                f1.push(nexx);
                f2.push(nexy);//进队列
            }
        }
    }
    for(int i=1;i<=n;i++){//输出
        for(int j=1;j<=m;j++) printf("%-5d",ans[i][j]);
        printf("\n");
    }
    return 0;
}

再来看下面这题:
202408311725083785844735.png
这题可以视作遍历二叉树,即上楼和下楼分别为节点。看代码:

#include <bits/stdc++.h>
using namespace std;

struct node{//floor存放一层,d存放到该层的步数
    int floor,d;
}now;

int n,a,b,k[201],dist;//n、a、b、k如题意,dist为临时变量
bool vis[201];//记录是否到达
queue<node> iq;//队列

int main(){
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n;i++){
        scanf("%d",&k[i]);
        vis[i]=false;
    }//初始化+读入
    iq.push((node){a,0});//起点入队
    vis[a]=true;//起点已访问过
    while(!iq.empty()){//循环直到队列空
        now=iq.front();//存放这次循环要处理的点
        iq.pop();//出队
        if(now.floor==b) break;//当已经到达终点时,退出循环。由于广搜可以保证搜索的步数逐渐增加,所以不会漏掉步数更少的情况
        dist=now.floor-k[now.floor];//临时记录(下楼)
        if(dist>=1 && dist<=n && !vis[dist]){//判断未超界且未访问过
            iq.push((node{dist,now.d+1}));//入队
            vis[dist]=1;//标记
        }
        dist=now.floor+k[now.floor];//临时记录(上楼)
        if(dist>=1 && dist<=n && !vis[dist]){//同上
            iq.push((node{dist,now.d+1}));
            vis[dist]=1;
        }
    }
    if(now.floor==b) printf("%d",now.d);
    else printf("-1");
    return 0;
}

这里注意不要忘记开vis数组,否则可能会死循环(出现环状结构时)。

结语
BFS是很重要的一个算法,只要想清楚自己的树是怎么样的就可以轻松完成程序。我是faryou,再见!