当前位置: 首页 > news >正文

广度优先搜索详解--BFS--蒟蒻的学习之路

 1.什么是广度优先搜索?

广度优先搜索(Breadth-First Search,简称BFS)是一种遍历或搜索树和图的算法,也称为宽度优先搜索,BFS算法从图的某个节点开始,依次对其所有相邻节点进行探索和遍历,然后再对这些相邻节点的相邻节点进行探索,直到遍历完所有的节点。

2.c++与c语言的实现的不同

c++ BFS算法使用队列来辅助实现,c语言往往通过数组来辅助实现(后面会有不同的样例来解释不同的语言的实现形式)c语言看起来可能有点啊难理解,需要通过模拟队列!

3.BFS的使用场景

一般来说广度优先搜索适用于解决两点之间的最短路径问题

广度优先搜索是从起点出发,以起点为中心,一圈一圈搜索的,一旦找到终点,记录之前走过的节点,这样就是一条最短路径

BFS常用于寻找最短路径,数据小的最短路径可以用DFS,大点的用DFS会超时,之前写过一道,这样子的题型

DFS/BFS算法在蓝桥杯竞赛中很常见。几乎每一年都会考到DFS/BFS算法!

4.BFS的使用步骤

将起始节点放入队列中,然后将起点标记为已经访问过,然后依次取出队列中的节点,访问其相邻节点,并将其加入队列。这样可以保证从起始节点出发,依次按照距离顺序遍历节点。因为它按照从起点到每个节点的距离来探索节点。

BFS算法通常使用队列来实现,BFS算法的具体步骤如下:

  1. 创建一个队列,将起始节点加入队列;
  2. 创建一个集合,用于存储已经访问过的节点;
  3. 从队列中取出一个节点,并将其标记为已访问;
  4. 访问该节点的所有相邻节点,如果相邻节点未被访问,则将其加入队列;
  5. 重复步骤3和步骤4,直到队列为空。

5.算法模板:

首先我们需要一个队列来辅助BFS实现,还需要一个初始化的输入数组,还有一个标记数组。先找到BFS的起点跟终点,确定好之后,先把起点vis==1,把起点入队,然后进入BFS函数,进入BFS函数一般先是一个大while循环,来管理队列的入队、出队。由于点都是二维的,我们一般都是用pair或者结构体来表示点,新建一个点来存储队头的信息,存完就可以让队头出队了。然后判断是否到达了目标结点,一个if判断,下面就是跟dfs一样,一个for循环遍历周围所有的点,不合法的直接continue掉,合法的标记完vis后入队,有的题目会有回溯,像在部分最短路搜索。

queue<node> q;
void bfs(){
    while(!q.empty()){
        node tmp=q.top();//node为(x,y)结构体
        q.pop();//出队
        if(到达目标终点){
            更新
            return;
        }
        //有的会有剪枝
        for(int i=0;i<m;i++){//m个方向
            int dx=tmp.x+bx[i];
            int dy=tmp.y+by[i];
            if(下标越界){
                continue;
            }
            if(已经被标记过了){
                continue;
            }
            //否则就是合法的
            vis[dx][dy]=1;//先标记
            q.push(node{dx,dy});//再新点入队
        }
    }
}

6.例题讲解 

P1135 奇怪的电梯 - 洛谷

 这里有一个需要注意的地方for输入的时候要记得从1开始因为上下娄底要用到这个准确的位置下标

#include<bits/stdc++.h>
using namespace std;
#define N 400
int a[N];//接收上下楼梯的值
int visu[N];//判断当前楼层是否被访问
int n, Start, End;
struct pos {//表示当前状态
    int level;//目前的当层楼层
    int step;//到当前楼层的步数
};
void bfs();
int main() {
    while (cin >> n) {
        if (n == 0)break;
        cin >> Start >> End;
        for (int i = 1; i <= n; i++) {
            visu[i] = 0;
            cin >> a[i];
        }
        bfs();
    }
    return 0;
}
void bfs() {
    pos cur, next;//定义两个变量
    cur.level = Start;//接受初始值的楼梯层数状态
    cur.step = 0;
    queue<pos>qu;//队列qu变量
    qu.push(cur);//输入cur
    visu[Start] = 1;//表示当前楼层已经被访问
    while (!qu.empty()) {//如果队列不为空
        cur = qu.front();//cur接受首元素位置
        qu.pop();//弹出首元素位置
        if (cur.level == End) {//如果起点等于终点//打印当前步数(开始错在此处,因为写成start1==end,start1是没有变化的,所以不行)
            printf("%d", cur.step);
            return;
        }
        next.level = cur.level + a[cur.level];//向上走
        next.step = cur.step + 1;//步数加一
        if (next.level <= n) {
            if (visu[next.level] == 0) {
                visu[next.level] = 1;
                qu.push(next);
            }
        }
        next.level = cur.level - a[cur.level];
        next.step = cur.step + 1;
        if (next.level >= 1) {
            if (visu[next.level] == 0) {
                visu[next.level] = 1;
                qu.push(next);
            }
        }
    }
    cout << "-1" << endl;//最后实在没有找到返回-1
    return;
}

已补上c语言表现形式

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int n, start, next;
int a[1000], vis[1000];
struct pos {
	int h, step;
}q[1000];
void bfs() {
	int front = 1, rear = 1;
	q[rear].h = start;
	q[rear].step = 0;
	rear++;
	vis[start] = 1;
	while (front < rear) {
		struct pos cur, net;
		cur = q[front];
		front++;

		if (cur.h == next) {
			printf("%d", cur.step);
			return;
		}

		net.h = cur.h + a[cur.h];
		net.step = cur.step + 1;
		if (net.h <= n && net.h >= 1 && vis[net.h] == 0) {
			vis[net.h] = 1;
			q[rear] = net;
			rear++;
		}

		net.h = cur.h - a[cur.h];
		net.step = cur.step + 1;
		if (net.h <= n && net.h >= 1 && vis[net.h] == 0) {
			vis[net.h] = 1;
			q[rear] = net;
			rear++;
		}
	}
	printf("-1");
	return;
}
int main() {
	scanf("%d%d%d", &n, &start, &next);
	for (int i = 1; i <= n; i++)scanf("%d", &a[i]);
	bfs();
	return 0;
}

相关文章:

  • 【哇! C++】类和对象(一)
  • ⭐ Unity 横向滑动列表 首尾相连 轮转图
  • 在Linux上安装和使用Docker
  • 嵌入式linux利用标准字符驱动模型控制多个设备方法
  • STM32 USB 设备的描述信息作用
  • 【ISO 14229-1:2023 UDS诊断(ECU复位0x11服务)测试用例CAPL代码全解析⑰】
  • git,gitea - tool - creat Gitea Empty Rep Dir
  • 【异常错误】pycharm debug view变量的时候显示不全,中间会以...显示
  • nginx负载均衡, 解决iphash不均衡的问题之consistent
  • 【时时三省】(C语言基础)用N-S流程图表示算法
  • ok113i平台——多媒体播放器适配
  • “让App玩捉迷藏:Android教育平板的‘隐身术’开发实录”
  • 尚硅谷爬虫note009
  • 第一章:前端性能的定义与指标
  • DeepSeek联网搜索
  • Docker:3、在VSCode上安装并运行python程序或JavaScript程序
  • windows系统本地部署DeepSeek-R1全流程指南:Ollama+Docker+OpenWebUI
  • GitLab 概念
  • Python自动化测试
  • 【分布式理论12】事务协调者高可用:分布式选举算法
  • 远如《月球背面》,近似你我内心
  • 央媒评网红质疑胖东来玉石定价暴利:对碰瓷式维权不能姑息
  • 受美关税影响,本田预计新财年净利下降七成,并推迟加拿大建厂计划
  • 福州千余公共道路泊车位装“智能地锁”续:运营公司被责令改正并罚款
  • 专访|韩国世宗研究所中国研究中心主任:李在明若上台将推行均衡外交
  • 山西省委常委李金科添新职