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

BFS,DFS带图详解+蓝桥杯算法题+经典例题

1.BFS和DFS的定义与实现方式

1.1 深度优先搜索(DFS)

基本概念:DFS 是一种用于遍历或搜索图或树的算法。它从起始节点开始,沿着一条路径尽可能深地探索下去,直到无法继续或者达到目标节点,然后回溯到上一个节点,继续探索其他路径。

实现方式

通常使用递归或者栈(Stack)来实现。在递归实现中,函数不断调用自身来深入探索下一个节点;在使用栈的实现中,将节点压入栈中,每次从栈顶取出节点进行处理,并将其未访问的邻接节点压入栈中。

例如,对于一个图结构 graph = {"A": ["B", "C"], "B": ["D"], "C": ["E"], "D": [], "E": []},从节点 "A" 开始 DFS 搜索,首先访问 "A",然后选择 "B" 进行深入探索,访问 "B" 后再访问 "D",当 "D" 没有未访问的邻接节点时,回溯到 "B",由于 "B" 的邻接节点都已访问,再回溯到 "A",接着选择 "C" 进行深入探索,以此类推。

1.2 广度优先搜索(BFS)

基本概念:BFS 也是一种用于遍历或搜索图或树的算法。它从起始节点开始,首先访问起始节点的所有邻接节点,然后再依次访问这些邻接节点的邻接节点,以此类推,一层一层地向外扩展,直到找到目标节点或者遍历完整个图或树。

实现方式

通常使用队列(Queue)来实现。将起始节点放入队列中,每次从队列头部取出一个节点进行处理,并将其未访问的邻接节点依次放入队列尾部。

例如,对于图结构 graph = {"A": ["B", "C"], "B": ["D"], "C": ["E"], "D": [], "E": []},从节点 "A" 开始 BFS 搜索,首先将 "A" 放入队列,然后取出 "A" 并访问它,将 "A" 的邻接节点 "B" 和 "C" 放入队列;接着从队列中取出 "B" 并访问它,将 "B" 的邻接节点 "D" 放入队列;再取出 "C" 并访问它,将 "C" 的邻接节点 "E" 放入队列,依此类推。

 2.基本代码实现

将上图转化为graph邻接表

graph={ "A":["B","C"],"B":["A","C","D"],"C":["A","B","D","E"],"D":["B","C","E","F"],"E":["C","D"],"F":["D"]}

2.1 DFS实现对上图的寻找

graph={ "A":["B","C"],"B":["A","C","D"],"C":["A","B","D","E"],"D":["B","C","E","F"],"E":["C","D"],"F":["D"]}
def bfs(graph,s):stack=[]seen=set()#建立一个空集合,用于后续检查元素是否已经存在于栈中stack.append(s)seen.add(s)while len(stack)>0:key=stack.pop()nodes=graph[key]for i in nodes:if i not in seen:stack.append(i)seen.add(i)# 如果不在集合中,向栈中添加,并在集合中标记print(key)
bfs(graph,"A")# A
# C
# E
# D
# F
# B

区别:queue.append()统一在右侧添加元素,DFS是利用pop()删除最右端的元素,而BFS是利用pop(0) 删除最左端的元素

2.2 BFS 实现对上图的寻找

graph={ "A":["B","C"],"B":["A","C","D"],"C":["A","B","D","E"],"D":["B","C","E","F"],"E":["C","D"],"F":["D"]}
def bfs(graph,s):queue=[]seen=set()queue.append(s)seen.add(s)while len(queue)>0:key=queue.pop(0)nodes=graph[key]for i in nodes:if i not in seen:queue.append(i)seen.add(i)print(key)
bfs(graph,"A")
# A
# B
# C
# D
# E
# F

3.BFS和DFS的区别,优缺点

3.1 区别

  • 搜索方式
    • DFS:从起始节点开始,沿着一条路径尽可能深地探索下去,直到无法继续或达到目标节点,然后回溯到上一个未完全探索的节点,继续探索其他路径,就像走迷宫时一直沿着一条路走到死胡同再回头。
    • BFS:从起始节点开始,先访问其所有相邻节点,然后再依次访问这些相邻节点的相邻节点,一层一层地向外扩展,如同水波一样向四周扩散。
  • 数据结构
    • DFS:通常使用递归或栈来实现。递归实现时,系统会自动使用栈来保存函数调用的上下文信息;也可以手动使用栈来存储待访问的节点。
    • BFS:使用队列来实现,先将起始节点放入队列,然后每次从队列中取出一个节点,访问其相邻节点并将未访问过的相邻节点放入队列。
  • 遍历顺序
    • DFS:遍历顺序是深度优先的,会先深入探索某一条路径上的节点,然后再回溯到其他分支。
    • BFS:遍历顺序是广度优先的,按照距离起始节点的远近依次访问节点,先访问距离近的节点,再访问距离远的节点。

3.2 优缺点

  • DFS
    • 优点:实现相对简单,对于某些问题,如寻找图中的连通分量、拓扑排序等,DFS 的递归性质使其代码简洁明了。在一些情况下,如果目标节点位于较深的层次,DFS 可能会更快地找到目标,因为它会优先沿着一条路径深入探索。
    • 缺点:可能会陷入无限循环,特别是在处理有环的图时,需要额外的机制来标记已访问的节点以避免重复访问。而且它不一定能找到最短路径,因为它是深度优先探索,可能会先找到一条较长的路径到达目标节点。
  • BFS
    • 优点:一定能找到从起始节点到目标节点的最短路径(如果存在),因为它是按照层次依次访问节点的。在处理无权图或边权都相等的图时,BFS 是寻找最短路径的理想算法。
    • 缺点:需要更多的空间来存储队列中的节点,特别是在图的规模较大时,可能会占用大量的内存。而且对于某些问题,其实现可能相对复杂一些,因为需要维护队列和处理节点的访问顺序。

4.DFS经典例题

4.1 矩阵最长递减路径问题

题意:计算每一个格子,由大递减到小所占的格子数

#矩阵最长递减路径
lis=[[1,1,3],[2,3,4],[1,0,5]]
m,n=3,3
def dfs(i,j,val):if i<0 or i==m:    #行出界return 0if j<0 or j==n:    #列出界return 0if lis[i][j]>=val: #递增,不符合题意return 0if (i,j) in dp:return dp[(i,j)]res=1res=max(res,1+dfs(i-1,j,lis[i][j]))  #向上res=max(res,1+dfs(i+1,j,lis[i][j]))  #向下res=max(res,1+dfs(i,j-1,lis[i][j]))  #向左res=max(res,1+dfs(i,j+1,lis[i][j]))  #向右dp[(i,j)]=res   #以键值对的形式保存到集合中return res
dp={}
for i in range(m):for j in range(n):res=dfs(i,j,100)print(res,end=' ')print( )
print(dp)
print(f'最短路径格子数为{max(dp.values())}')
#将取出全部键值对中的值,并输出最大值#输出结果
1 1 2 
3 4 5 
2 1 6 
{(0, 0): 1, (0, 1): 1, (0, 2): 2, (2, 1): 1,(2, 0): 2, (1, 0): 3, (1, 1): 4, (1, 2): 5, (2, 2): 6}
最长路径格子数为6

 下图为从递减路径最长的一条,即从右下角的单元格出发的遍历流程图。黑色笔标注的数字代表单元格内的数字,红色笔标注的数字为走过的格子数(画图潦草,请各位读者见谅)

4.2 海域污染问题

N,M=list(map(int,input().split(',')))
lis=[]
n=N
while n>0:a=list(map(int,input()))lis.append(a)n-=1
def dfs(x,y):if x<0 or x==N:  # 行出界return 0if y<0 or y==M:  # 列出界return 0if lis[x][y]==0: # 坐标值为0return 0lis[x][y]=0    #将遍历到的不是0的数都变成0dfs(x-1,y)     # 向上dfs(x+1,y)     # 向下dfs(x,y-1)     # 向左dfs(x,y+1)     # 向右
count=0
for i in range(N):for j in range(M):if lis[i][j]==1:dfs(i,j)count+=1
print(count)

输入

4,5
11001
10001
00100
01100

 输出

3

4.3 最大的油田问题

lis=[[1,1,0,0,1],[0,0,0,1,0],[0,0,0,1,1],[1,1,0,1,1]]
hang=len(lis)
lie=len(lis[0])
ans=0
def dfs(x,y):if x>=0 and x<hang and y>=0 and y<lie and lis[x][y]==1:lis[x][y]=0return 1+dfs(x-1,y)+dfs(x+1,y)+dfs(x,y-1)+dfs(x,y+1)else:return 0
for i in range(hang):for j in range(lie):area=dfs(i,j)if area>ans:ans=area
print(ans)
# 5

5.BFS经典例题

5.1 蓝桥杯算法模板题--走迷宫

from collections import deque
N, M = 5, 5
a = [[1, 0, 1, 1, 0][1, 1, 0, 1, 1],[0, 1, 0, 1, 1],[1, 1, 1, 1, 1],[1, 0, 0, 0, 1]
]
n, m, c, d = 1, 1, 5, 5
# 因为矩阵下标从 0 开始,将目标坐标转换为 0 索引
c -= 1
d -= 1
n-=1
m-=1dx = [0, 1, 0, -1]  # 可以在行方向上移动的四个方向:右、下、左、上
dy = [1, 0, -1, 0]  # 可以在列方向上移动的四个方向:右、下、左、上# 标记矩阵,用于记录节点是否已经访问过
visited = [[False] * M for _ in range(N)]def bfs(x, y):# 创建队列,队列元素为 (x, y, steps)queue = deque([(x, y, 0)])visited[x][y] = Truewhile queue:cur_x, cur_y, steps = queue.popleft()# 到达目标点if cur_x == c and cur_y == d:return stepsfor i in range(4):  # 在四个方向上尝试移动new_x = cur_x  + dx[i]new_y = cur_y  + dy[i]# 检查新坐标是否合法且未访问过if 0 <= new_x < N and 0 <= new_y < M and a[new_x][new_y] == 1 and not visited[new_x][new_y]:visited[new_x][new_y] = Truequeue.append((new_x, new_y, steps + 1))return -1 # 如果不满足上述情况返回-1print(bfs(n,m))

标准提交代码:

from collections import dequeN,M=list(map(int,input().split()))
a=[list(map(int,input().split())) for _ in range(N)]
n,m,c,d=list(map(int,input().split()))
c -= 1
d -= 1
dx = [0, 1, 0, -1]  
dy = [1, 0, -1, 0]  visited = [[False] * M for _ in range(N)]
def bfs(x, y):queue = deque([(x, y, 0)])visited[x][y] = Truewhile queue:cur_x, cur_y, steps = queue.popleft()        if cur_x == c and cur_y == d:return stepsfor i in range(4):  new_x = cur_x  + dx[i]new_y = cur_y  + dy[i]          if 0 <= new_x < N and 0 <= new_y < M and a[new_x][new_y] == 1 and not visited[new_x][new_y]:visited[new_x][new_y] = Truequeue.append((new_x, new_y, steps + 1))return -1
print(bfs(n-1,m-1))

5.2 艰难旅程

from collections import dequedef bfs(val,st_row,st_col):# val为二维列表,st_row,st_col为起始坐标row=len(val)col=len(val[0])arrived=[[False for j in range(row)] for i in range(col)]# 二维列表存储地图上的每个方格是否到达过,初始标记为Flasemoverow=[0,1,0,-1]movecol=[1,0,-1,0]# 定义四个方向,以实现向上下左右移动ans=1queue=deque([(st_row,st_col)])arrived[st_row-1][st_col-1]=True  # 因为python是0索引,坐标值减1# 将起始坐标放入队列中,记录此点已到达,标记为Truewhile queue:# queue不为空的时候x,y=queue.popleft()# 从左端删除并返回位置坐标for i in range(4):newrow=x+moverow[i]newcol=y+movecol[i]# 向四个方向移动if newrow>row or newrow<=0 or newcol>col or newcol<=0:continue# 出界if not arrived[newrow-1][newcol-1] and val[newrow-1][newcol-1]!=val[x-1][y-1]:# 满足条件,未被标记,单元格内值不同queue.append((newrow,newcol))arrived[newrow-1][newcol-1]=True# 添加至队列并标记以走过ans+=1return ans
val= [[1, 0, 1, 1],[1, 0, 1, 0],[0, 1, 0, 1],[0, 0, 1, 1],
]
result = bfs(val,3,3)
print(result)# 11

相关文章:

BFS,DFS带图详解+蓝桥杯算法题+经典例题

1.BFS和DFS的定义与实现方式 1.1 深度优先搜索&#xff08;DFS&#xff09; 基本概念&#xff1a;DFS 是一种用于遍历或搜索图或树的算法。它从起始节点开始&#xff0c;沿着一条路径尽可能深地探索下去&#xff0c;直到无法继续或者达到目标节点&#xff0c;然后回溯到上一个…...

「清华大学、北京大学」DeepSeek 课件PPT专栏

你要的 这里都打包好啦&#xff0c;快快收藏起来&#xff01; 名称 链接 团队简介 类型 DeepSeek——从入门到精通 1️⃣ DeepSeek从入门到精通「清华团队」 清华大学新闻与传播学院 新媒体研究中心 元宇宙文化实验室 PPT课件 DeepSeek如何赋能职场应用? ——从提示语…...

如何在 Github 上获得 1000 star?

作为程序员&#xff0c;Github 是第一个绕不开的网站。我们每天都在上面享受着开源带来的便利&#xff0c;我相信很多同学也想自己做一个开源项目&#xff0c;从而获得大家的关注。然而&#xff0c;理想很丰满&#xff0c;现实却是开发了很久的项目仍然无人问津。 最近&#x…...

on-policy对比off-policy

目录 持续更新。。。 on-policy与off-policy的定义 Q-learning属于on-policy算法还是off-policy算法&#xff1f; 为什么off-policy适用于从离线经验或多种探索策略中学习&#xff0c;明明 On-policy 也可以基于探索学习的啊&#xff1f; 重要性权重方法 off-policy方法可…...

标准卡尔曼滤波

1.状态转移方程和观测方程 状态转移方程 x k A x k − 1 B u k w k x_k A x_{k-1} Bu_k w_k xk​Axk−1​Buk​wk​ x k x_k xk​&#xff1a;k时刻的 状态向量&#xff0c;理论上的真实状态。 x k − 1 x_{k-1} xk−1​&#xff1a;k-1时刻的 状态向量&#xff0c;理论…...

主流区块链

文章目录 主流链1. Solana特点&#xff1a;适用场景&#xff1a;工具链&#xff1a; 2. Binance Smart Chain (BSC)特点&#xff1a;适用场景&#xff1a;工具链&#xff1a; 3. Avalanche特点&#xff1a;适用场景&#xff1a;工具链&#xff1a; 4. Polkadot特点&#xff1a;…...

pytorch中有哪些损失函数

L1Loss 计算预测值 ypred 和真实值 ytrue 之间的平均绝对误差&#xff08;MAE&#xff09;&#xff0c;公式为 L ( y p r e d , y t r u e ) 1 n ∑ i 1 n ∣ y p r e d i − y t r u e i ∣ L(y_{pred},y_{true})\frac1n\sum^n_{i1}|y^i_{pred}-y^i_{true}| L(ypred​,ytru…...

【设计模式有哪些】

一、创建型模式&#xff08;Creation Patterns&#xff09; 1. 单例模式&#xff08;Singleton&#xff09; 核心思想&#xff1a;保证一个类仅有一个实例&#xff0c;并提供全局访问点。实现方式&#xff1a;public class Singleton {// 1. 私有静态实例&#xff0c;volatil…...

基于SpringBoot+Vue的幼儿园管理系统+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、教师、普通用户功能模块&#xff1a;用户管理、教师管理、班级管理、幼儿信息管理、会议记录管理、待办事项、职工考核、请假信息、缴费信息、体检管理、资源管理、原料管理、菜品信息管理等技术选型&#xff1a;SpringBoot&#xff0…...

默认参数 d = {} 的陷阱

默认参数 d {} 的陷阱 问题需求思路代码实现默认参数d {}的陷阱解决办法1、在函数外为每个字符串创建空字典统计词频2、函数改为每次调用时创建新字典&#xff0c;避免数据污染 举一反三 问题需求 统计两个字符串的中文词语出现次数 思路 先使用jieba库分词功能处理字符串…...

Python 常用内建模块-argparse

目录 argparse 小结 argparse 在命令行程序中&#xff0c;经常需要获取命令行参数。Python内置的sys.argv保存了完整的参数列表&#xff0c;我们可以从中解析出需要的参数&#xff1a; # copy.py import sys print(sys.argv) source sys.argv[1] target sys.argv[2] # TOD…...

案例5_3: 6位数码管静态显示

文章目录 文章介绍效果图仿真图复习知识&#xff1a;代码思考 文章介绍 第5章 学习数码管&#xff0c;使用6位数码管进行静态显示 效果图 仿真图 新建一个干净的5_3文件夹&#xff0c;用于存放新画的仿真图 除单片机最小系统外&#xff0c;新增3个元器件&#xff0c;分别是&…...

Profinet转Modbus RTU/TCP以太网通讯处理器

Profinet转Modbus RTU/TCP以太网通讯处理器 在当今的工业自动化领域&#xff0c;各种通讯协议和标准层出不穷。 其中&#xff0c;Profinet和Modbus作为两种广泛应用的通讯协议&#xff0c;分别在不同的应用场景中发挥着重要作用。 然而&#xff0c;当需要将这两种协议进行转换…...

3倍训练速度+40%显存节省!Mamba+Transformer 仅用一半时间,性能提升80%!

在人工智能领域&#xff0c;Mamba与Transformer的结合正在成为研究热点&#xff0c;为自然语言处理和多模态任务带来新的突破。 最新研究表明&#xff0c;通过将Mamba架构与Transformer的强大编码能力相结合&#xff0c;模型在处理复杂的多模态数据时的效率提升了50%&#xff…...

春秋云境刷题1

CVE-2022-29464 靶标介绍&#xff1a; WSO2文件上传漏洞&#xff08;CVE-2022-29464&#xff09;是Orange Tsai发现的WSO2上的严重漏洞。该漏洞是一种未经身份验证的无限制任意文件上传&#xff0c;允许未经身份验证的攻击者通过上传恶意JSP文件在WSO2服务器上获得RCE。 Git…...

台式机电脑组装---电源

台式机电脑组装—电源 22 33 主板供电是聚集了12V&#xff0c;5V,3.3V的24pin CPU供电的话主要是12V的44pin供电 44pin合并之后&#xff0c;就是8pin 55 SATA硬盘会使用饼io口取电&#xff0c;从电源获取12v,5v,3.3v的电 33...

10-BST(二叉树)-建立二叉搜索树,并进行前中后遍历

题目 来源 3540. 二叉搜索树 - AcWing题库 思路 建立二叉搜索树&#xff08;注意传参时用到了引用&#xff0c;可以直接对root进行修改&#xff09;&#xff0c;同时进行递归遍历&#xff1b;遍历可以分前中后三种写&#xff0c;也可以用标志来代替合在一起。其余详见代码。…...

蓝桥杯备考:贪心问题之淘淘摘苹果

这是淘淘摘苹果普通版&#xff0c;很可爱的一道题&#xff0c;我们不多陈述&#xff0c;直接上代码 #include <iostream> using namespace std; const int N 15; int a[N]; int main() {for(int i 1;i<10;i){cin >> a[i];}int x;cin >> x;x30;int cnt …...

VSTO(C#)Excel开发 系列目录 含源码发布

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…...

在 Ubuntu 下通过 Docker 部署 Nginx+PHP-FPM 服务器

引言 大家好&#xff0c;今天我们来聊聊如何在 Ubuntu 下通过 Docker 部署 Nginx 和 PHP-FPM 服务器。Docker 是一个开源的容器化平台&#xff0c;可以轻松地打包、分发和管理应用程序。而 Nginx 是一个高性能的 HTTP 服务器和反向代理服务器&#xff0c;PHP-FPM 则是 PHP 的一…...

Git使用和原理(3)

1.远程操作 1.1分布式版本控制系统 我们⽬前所说的所有内容&#xff08;⼯作区&#xff0c;暂存区&#xff0c;版本库等等&#xff09;&#xff0c;都是在本地&#xff01;也就是在你的笔记本或者 计算机上。⽽我们的 Git 其实是分布式版本控制系统&#xff01;什么意思呢&a…...

【ELK】节省存储 之 压缩存储方式调整

目录 集群版本&#xff1a; 7.17.6 解释几个概念&#xff1a; 段&#xff08;Segment&#xff09; 合并(Merge) 索引设置&#xff1a; 压缩方式(index.codec)&#xff1a; 测试设置前提条件 对比 在创建的时候指定压缩类型&#xff08;index.codec&#xff09; 对比 在…...

导出的使用

在web开发中&#xff0c;导出是很常见的一个功能&#xff0c;当我进行个人项目练习的时候&#xff0c;导出的时候无法控制列宽以及居中样式&#xff0c;后续发现导出插件无法进行修改&#xff0c;整个插件较为简便易懂的同时&#xff0c;对于EX的控制较为简陋&#xff0c;很多东…...

博客图床 VsCode + PigGo + 阿里云OSS

关键字 写博客&#xff0c;图床&#xff0c;VsCode&#xff0c;PigGo&#xff0c;阿里云OSS 背景环境 我想把我在本地写的markdown文档直接搬到CSDN上和博客园上&#xff0c;但是图片上传遇到了问题。我需要手动到不同平台上传文件&#xff0c;非常耗费时间和经历。 为了解决…...

鸿蒙开源硬件:重构万物智联生态的底层基座与未来机遇

一、从生态裂变到产业重构&#xff1a;开源鸿蒙的崛起之路 自 2020 年开源至今&#xff0c;OpenHarmony 社区以惊人的发展速度重塑智能终端操作系统格局。数据显示&#xff0c;其代码量已从初始的 700 万行激增至 1.2 亿行&#xff0c;汇聚超 8200 名开发者及 70 余家核心共建…...

C++之list类及模拟实现

目录 list的介绍 list的模拟实现 定义节点 有关遍历的重载运算符 list的操作实现 &#xff08;1&#xff09;构造函数 (2)拷贝构造函数 &#xff08;3&#xff09;赋值运算符重载函数 &#xff08;4&#xff09;析构函数和clear成员函数 &#xff08;5&#xff09;尾…...

SwinTransformer 改进:添加DoubleAttention模块提升上下文语义提取能力

目录 1. DoubleAttention模块 2. SwinTransformer + DoubleAttention 3. 完整代码 Tips:融入模块后的网络经过测试,可以直接使用,设置好输入和输出的图片维度即可 1. DoubleAttention模块 DoubleAttention 是一种用于计算机视觉任务的注意力机制,旨在通过双重注意力机制…...

在Electron中实现实时下载进度显示的完整指南

在开发Electron应用时&#xff0c;提供良好的用户体验至关重要&#xff0c;尤其是在下载大文件时。用户需要知道下载进度、预计完成时间以及当前下载速度。本文将详细介绍如何在Electron应用中实现实时下载进度显示功能&#xff0c;从主进程到渲染进程的完整流程。 技术栈是ele…...

java生成一个可以下载的word文件

在 Java 里&#xff0c;你能够借助 Apache POI 库来生成 Word 文件&#xff0c;并且实现文件下载功能。下面为你详细介绍实现步骤和示例代码。 1. 添加依赖 若使用 Maven 项目&#xff0c;需在 pom.xml 里添加 Apache POI 的依赖&#xff1a; <dependencies><depen…...

MacBook部署达梦V8手记

背景 使用Java SpringBootDM开发Web应用&#xff0c;框架有License&#xff0c;OSX加载dll失败&#xff0c;安装了Windows 11&#xff0c;只有一个C盘&#xff0c;达梦安装后因为C盘权限问题&#xff0c;创建数据库失败&#xff0c;遂采用Docker容器方式部署。 下载介质 官网在…...