from collections import deque
def bfs_template(start):
visited = set() # 已访问集合(防重复/环检测)
queue = deque([start]) # 初始化队列(可携带初始参数如步数)
while queue:
level_size = len(queue) # 当前层节点数(用于层次遍历统计)
for _ in range(level_size): # 层次处理循环(非必须)
current = queue.popleft()
# 终止条件检测(根据问题灵活设置)
if is_target(current):
return result
# 生成相邻节点(核心拓展逻辑)
for neighbor in get_neighbors(current):
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
return default_result # 无解情况
四大必改模块说明
1. 状态表示
# 示例1:二维坐标 (x, y)
current = (x, y)
# 示例2:字符串状态(如单词变换)
current = "hot"
# 示例3:复合状态(携带额外参数)
current = (x, y, steps, keys_held)
2.终止条件
def is_target(state):
# 示例1:到达迷宫终点
return state == (N-1, M-1)
# 示例2:字符串变为目标词
return state == "cog"
# 示例3:收集所有钥匙(位运算校验)
return state[2] == 0b1111
3.邻居生成
def get_neighbors(state):
# 示例1:四方向移动
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
return [(state[0]+dx[i], state[1]+dy[i]) for i in range(4)]
# 示例2:单词字符变换
return [word[:i]+c+word[i+1:] for i in range(len(word)) for c in 'abcdefghijklmnopqrstuvwxyz']
# 示例3:状态机转移(如自动机问题)
return next_states_map[state]
4.状态去重
# 根据问题选择编码方式:
visited.add(state) # 原始对象(需可哈希)
visited.add((x, y)) # 元组编码
visited.add(",".join(map(str, pos))) # 字符串编码
visited.add(bitmask) # 位压缩编码
注意要点:
- 队列初始化:起始状态必须合法
- 去重策略:状态编码决定空间复杂度
- 层次处理:
level_size
循环实现按层统计,层次遍历就像给每个探索点贴"第几步到达"的标签 - 剪枝优化:在入队前过滤无效状态
- 路径记录:可用字典保存前驱节点(如需要输出路径)
举例
二叉树层序遍历
def levelOrder(root):
if not root: return []
q = deque([root])
res = []
while q:
level = []
for _ in range(len(q)):
node = q.popleft()
level.append(node.val)
if node.left: q.append(node.left)
if node.right: q.append(node.right)
res.append(level)
return res
迷宫最短路径
def shortestPath(maze, start, destination):
dirs = [(0,1),(0,-1),(1,0),(-1,0)]
m, n = len(maze), len(maze[0])
q = deque([(start[0], start[1], 0)])
visited = set()
while q:
x, y, steps = q.popleft()
if [x,y] == destination: return steps
if (x,y) in visited: continue
visited.add((x,y))
for dx, dy in dirs:
nx, ny = x+dx, y+dy
if 0<=nx<m and 0<=ny<n and maze[nx][ny]==0:
q.append((nx, ny, steps+1))
return -1
字符串接龙
def judge(s1,s2): #判断是否可以转移
count=0
for i in range(len(s1)):
if s1[i]!=s2[i]:
count+=1
return count==1
n=int(input())
beginstr,endstr=map(str,input().split())
if beginstr==endstr:
print(0)
exit()
strlist=[] #所有节点,帮助判断neibor子节点
for i in range(n):
strlist.append(input())
# use bfs
visit=[False for i in range(n)] #visited访问标识
queue=[[beginstr,1]] #deque初始化
while queue:
str,step=queue.pop(0) #没用层序遍历,而是用了step记录长度,如果要路径就是列表
if judge(str,endstr): #判断最终条件
print(step+1)
exit() #退出
for i in range(n):
if visit[i]==False and judge(strlist[i],str): #判断条件,可转移且未访问
visit[i]=True
queue.append([strlist[i],step+1]) #入列并将step加1
print(0) #默认输出,遍历完了都没有istarget(),比如无法转换的输出
完全可达性
def is_reachable_all_nodes(n, edges, start):
# 构建邻接表,输入edge->[1,2]即1到2有一条路径
adj = [[] for _ in range(n)]
for u, v in edges:
adj[u].append(v)
visited = set()
queue = deque([start]) #初始化
visited.add(start) #已经访问列表
while queue:
node = queue.popleft()
# 邻居生成:遍历所有出边
for neighbor in adj[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
# 完全可达判定:已访问节点数等于总节点数
return len(visited) == n