蓝桥杯BFS/DFS

一、BFS通用模板

BFS是广度优先搜索。适用于最短路径、最小步数、层序遍历、连通块计数

网格图模拟BFS:给定一个二维网格,以及一些初始位置,并说明初始位置的蔓延条件,最后求一些计数或者最值问题。

思路:通过队列q存储位置。初始值即为初始位置,每次考虑当前位置(x,y)的四周,尝试蔓延。

python 复制代码
from collections import deque

# 迷宫类 BFS 模板(网格)
def bfs_grid(start, end, grid):
    n = len(grid)
    m = len(grid[0])
    # 方向数组:上下左右
    dirs = [(-1,0), (1,0), (0,-1), (0,1)]
    # 访问标记/距离数组
    dist = [[-1]*m for _ in range(n)]
    q = deque()
    # 初始化起点
    sx, sy = start
    dist[sx][sy] = 0
    q.append((sx, sy))
    
    while q:
        x, y = q.popleft()
        # 到达终点,直接返回最短距离
        if (x, y) == end:
            return dist[x][y]
        # 遍历四个方向
        for dx, dy in dirs:
            nx = x + dx
            ny = y + dy
            # 边界判断 + 未访问 + 可通行
            if 0 <= nx < n and 0 <= ny < m and dist[nx][ny] == -1 and grid[nx][ny] == 0:
                dist[nx][ny] = dist[x][y] + 1
                q.append((nx, ny))
    # 无法到达
    return -1

题目描述

输入描述

输出描述

输入输出示例

输入

4 5

.g...

.....

..g..

.....

2

输出

gggg.

gggg.

ggggg

.ggg.

python 复制代码
# 输入地图的行数和列数  
n, m = map(int, input().split())  
# 初始化一个空的地图列表  
Map = []  
# 根据输入的行数和列数,逐行读取地图数据并添加到Map列表中  
for _ in range(n):  
    Map.append(list(input()))  
  
# 输入需要进行的bfs次数  
k = int(input())  
# 初始化一个空队列,用于存储起点坐标  
q = []  
  
# 遍历整个地图,将所有起点(标记为'g')的坐标加入队列  
for i in range(n):  
    for j in range(m):  
        if Map[i][j] == 'g':  
            q.append((i, j))  

# 定义一个函数,用于检查给定的坐标是否在地图范围内且是可以通过的(标记为'.')  
def check(x, y):  
    if 0 <= x < n and 0 <= y < m and Map[x][y] == '.':  
        return True  
    return False  
# 定义bfs函数  
def bfs():  
    global q  # 声明q为全局变量,以便在函数内部修改  
    cnt = len(q)  # 初始化计数器,记录当前队列中的元素数量  
    while cnt > 0:  
        x, y = q.pop(0)  # 取出队列中的第一个元素(坐标)  
        # 遍历四个方向(上、下、左、右)  
        for dx, dy in [[-1, 0], [1, 0], [0, -1], [0, 1]]:  
            cx, cy = dx + x, dy + y  # 计算新的坐标  
            # 如果新坐标在地图范围内且是可以通过的  
            if check(cx, cy):  
                # 将新坐标加入队列  
                q.append((cx, cy))  
                # 标记新坐标已经访问过  
                Map[cx][cy] = 'g'  
        cnt -= 1  # 计数器减一  
# 执行k次bfs操作  
for i in range(k):  
    bfs()  
  
# 输出最终的地图  
for i in Map:  
    print(''.join(i))

题目描述

输入描述

输出描述

输出一个整数表示答案。

输入输出示例

输入

7

.......

.##....

.##....

....##.

..####.

...###.

.......

输出

1

python 复制代码
#_________________________________________________________ BFS
N=int(input())
Map=[list(input()) for _ in range(N)]
directions=[[-1,0],[1,0],[0,-1],[0,1]]
visited=[[0]*N for _ in range(N)]
# 问题二flag 没有在每个岛重置
flag=True
q=[]

def bfs():
  #问题一BFS 只处理了一个点
  # x,y=q.pop(0)
  # 默认会被淹没
  
  global flag
  # 队列不为空
  while q:
    x,y=q.pop(0)
    # 找到满足条件的情况
    if Map[x-1][y]=='#' and Map[x+1][y]=='#' and Map[x][y-1]=='#' and Map[x][y+1]=='#':
      flag=False
      # 问题三这个岛剩下的点 visited 没标记
      # return
    for dx,dy in directions:
      cx=dx+x
      cy=dy+y
      if 0<=cx<N and 0<=cy<N and Map[cx][cy]=='#' and visited[cx][cy]==0:
        visited[cx][cy]=1
        q.append((cx,cy))
ans=0   


for i in range(N):
  for j in range(N):
    flag=True
    # 访问起始点
    if Map[i][j]=='#' and visited[i][j]==0:
      visited[i][j]=1
      q.append((i,j))
      bfs()
      # 会被淹没
      if flag:
        ans+=1

print(ans)   

二、DFS通用模板

DFS:深度优先搜索。适用于:迷宫最短路径、最小步数、层序遍历、连通块

递归调用函数查找

python 复制代码
# 迷宫类 DFS 模板(网格)
visited = set()  # 或二维数组
dirs = [(-1,0), (1,0), (0,-1), (0,1)]

def dfs(x, y, grid, n, m):
    # 边界判断 + 已访问 + 不可通行
    if x < 0 or x >= n or y < 0 or y >= m or (x,y) in visited or grid[x][y] != 0:
        return
    # 标记访问
    visited.add((x, y))
    # 遍历四个方向
    for dx, dy in dirs:
        dfs(x+dx, y+dy, grid, n, m)

输入描述

输入描述

输出描述

python 复制代码
import os
import sys
import copy

# 设置递归深度(防止 DFS 层数过多爆栈)
sys.setrecursionlimit(1500000)

# 输入棋盘大小 n×n
n=int(input())

# vis:访问标记数组
# vis[i][j] = 1 表示该格子已经走过(路径不能重复走)
vis=[[0]*n for _ in range(n)]

# lie:每一列还需要走多少个格子
lie=list(map(int,input().split()))

# hang:每一行还需要走多少个格子
hang=list(map(int,input().split()))

# 目标步数(总路径长度)
# 因为每走一个格子,会同时消耗 行+列 各1
# 所以总步数 = (行总和 + 列总和) / 2
tar=(sum(hang)+sum(lie))//2

# 四个方向(右、下、上、左)
dirs=[[0,1],[1,0],[-1,0],[0,-1]]

# 用来记录最终路径(字符串形式)
p=""

# DFS函数:
# x,y:当前位置
# path:路径(用字符串记录)
# bu:当前已经走的步数
def dfs(x,y,path,bu):
  global p

  # 标记当前格子已访问
  vis[x][y]=1

  # 当前行、列需求减1(表示走了这个点)
  hang[x]-=1
  lie[y]-=1

  # ===== 剪枝1:行约束 =====
  # 如果当前行已经满足(变成0)
  # 那么前面的行必须也已经满足,否则不合法
  if hang[x]==0:
    for i in range(x):
      if hang[i]>0:
        return   # 不满足,直接剪枝

  # ===== 剪枝2:列约束 =====
  if lie[y]==0:
    for i in range(y):
      if lie[i]>0:
        return   # 不满足,剪枝

  # ===== 终点判断 =====
  # 如果走到了右下角
  if x==n-1 and y==n-1:

    # 判断是否满足:
    # 1. 所有行列刚好用完
    # 2. 步数等于目标步数
    if sum(hang)==0 and sum(lie)==0 and bu==tar:
      p=path   # 记录路径
      return   # 找到答案,结束
    else:
      return   # 虽然到终点,但不合法

  # ===== 枚举四个方向 =====
  for xq,yq in dirs:
    xi,yi=x+xq,y+yq

    # 条件:
    # 1. 不越界
    # 2. 没访问过
    # 3. 该行还有剩余需求
    # 4. 该列还有剩余需求
    if 0<=xi<n and 0<=yi<n and vis[xi][yi]!=1 and hang[xi]>0 and lie[yi]>0:

      # 递归搜索
      dfs(xi,yi,path+"/"+str(xi*n+yi),bu+1)

      # ===== 回溯(非常关键)=====
      vis[xi][yi]=0      # 恢复未访问
      hang[xi]+=1        # 恢复行需求
      lie[yi]+=1         # 恢复列需求


# 从起点 (0,0) 开始
# 初始路径为 "0"
# 初始步数为 1(已经走了起点)
dfs(0,0,"0",1)

# 输出路径(按题目要求格式)
for i in p.split("/"):
  print(i,end=" ")
相关推荐
Tanecious.8 小时前
蓝桥杯备赛:Day1-P1101 单词方阵
c语言·c++·蓝桥杯
仟濹11 小时前
【算法打卡day37(2026-04-04 周六)】DFS专项训练4-枚举专项训练 1-全部是蓝桥杯真题
算法·蓝桥杯·深度优先
承渊政道12 小时前
【优选算法】(实战:栈、队列、优先级队列高频考题通关全解)
数据结构·c++·笔记·学习·算法·leetcode·宽度优先
沙雕不是雕又菜又爱玩14 小时前
P12121 [蓝桥杯 2024 省 B 第二场] 进制(C++)
蓝桥杯
w61001046615 小时前
图论总结-day66
数据结构·算法·深度优先·图论
Hello eveybody15 小时前
图论简述+图论考试要点(C++)
c++·深度优先·图论
故事和你9115 小时前
洛谷-算法1-1-模拟与高精度4
开发语言·数据结构·c++·算法·蓝桥杯·动态规划
小年糕是糕手16 小时前
【35天从0开始备战蓝桥杯 -- Day8】
数据结构·c++·算法·leetcode·蓝桥杯
Tanecious.16 小时前
蓝桥杯备赛:Day4-P10387 训练士兵
c++·蓝桥杯