目录
一、bfs遍历
bfs遍历:一般用来求最短路
给节点分层,从起点,每次把第一步能走到的点全部走一遍。
bfs遍历的步骤
1、将起点入队列,打标记,更行距离。
2、当队列非空。
2.1、取出对首元素u。
2.2、当u是终点,break。
2.3、对于和u相连的所以点v。只要v未标记,将v入队列,打标记,更新距离
来一个模版题:熟悉bfs的应用
题目链接:最少操作数
这道题直接按照bfs的遍历的步骤来模拟即可
from collections import deque
def bfs(s):
# s:表示对首元素
# vis:标记数组,与距离数组二和一
vis = [-1] * 100100
q = deque()
# 1、对首元素入队
q.append(s)
vis[s] = 0
# 2、判断队列是否为空
while len(q) != 0:
# 2.1、取出对首元素
u = q.popleft()
# 2.2、当现在已经到达终点时,直接返回答案
if u == m:
return vis[u]
# 2.3、遍历对于与u相连的v
for v in [u + 1, u - 1, u * 2]:
# 特判:看是否越界,是否已经被标记
if 0 <= v <= 100000 and vis[v] == -1:
# 更新距离,打标记
vis[v] = vis[u] + 1
# 将v打入队列
q.append(v)
n, m = map(int, input().split())
print(bfs(n))
题目链接:混镜之地4
import sys
from collections import deque
def bfs(x, y, dis):
# (x, y) 代表起点,dic存储最短距离
# 初始化队列
vis = [[0] * m for _ in range(n)]
q = deque()
# 把起点放到队列,打标记
q.append([x, y])
vis[x][y] = 1
dis[x][y] = 0
while len(q) != 0:
# 在取出元素的时候注意更新
x, y = q.popleft()
for x_v, y_v in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
xx, yy = x + x_v, y + y_v
# 判断是否越界,是否标记,是否有障碍
if 0 <= xx < n and 0 <= yy < m and vis[xx][yy] == 0 and li[xx][yy] != '#':
q.append([xx, yy])
vis[xx][yy] = 1
dis[xx][yy] = dis[x][y] + 1
n, m = map(int, input().split())
A, B, C, D = map(int, input().split())
A -= 1
B -= 1
C -= 1
D -= 1
li = [list(input()) for _ in range(n)]
E = int(input())
inf = 10e9
# dis表示起点到每一个点的最短距离,之所以用inf原因可能永远到达不了终点
dis1 = [[inf] * m for _ in range(n)]
# dis2a 表示从终点到达每个点的最短距离
dis2 = [[inf] * m for _ in range(n)]
bfs(A, B, dis1)
if dis1[C][D] <= E:
# 如果到终点的最短路下于等于现有的能量。可以直接打印最短距离
print(dis1[C][D])
sys.exit()
bfs(C, D, dis2)
# print(dis1)
# print(dis2)
ans = inf
# 枚举所有的圣泉,找到所需要时间最短的路
for i in range(n):
for j in range(m):
if li[i][j] == 'V':
if dis1[i][j] <= E:
# dis2[i][j] - E + dis1[i][j] :表示需要再圣泉呆的时间
# dis1[i][j]:表示到达圣泉所需要的时间
# dis2[i][j]:表示从圣泉到终点所需要的时间
ans = min(ans, (dis2[i][j] - E + dis1[i][j]) + dis1[i][j] + dis2[i][j])
if ans != inf:
print(ans)
else:
print('No')
题目链接:走迷宫
from collections import deque
def bfs():
inf = 1e18
# vis:表示标记数组
vis = [[0] * m for _ in range(n)]
# il:表示距离数组
il = [[inf] * m for _ in range(n)]
# q:表示队列
q = deque()
# 起点入队:
q.append((x1, y1))
# 打标记:
vis[x1][y1] = 1
# 更新距离:
il[x1][y1] = 0
while len(q) != 0:
x, y = q.popleft()
if x == x2 and y == y2:
return il[x][y]
for x_d, y_d in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
xx = x_d + x
yy = y_d + y
if 0 <= xx < n and 0 <= yy < m and Map[xx][yy] == 1 and vis[xx][yy] == 0:
q.append((xx, yy))
vis[xx][yy] = 1
il[xx][yy] = il[x][y] + 1
return -1
n, m = map(int, input().split())
Map = [list(map(int, input().split())) for _ in range(n)]
x1, y1, x2, y2 = map(int, input().split())
x1 -= 1
y1 -= 1
x2 -= 1
y2 -= 1
print(bfs())
题目链接:马的遍历
注意:在写代码的时候一定不能太着急,这题的代码一开始把y_d写成了x_d检查了好久好久。
from collections import deque
def bfs():
#
il = [[-1] * m for _ in range(n)]
vis = [[0] * m for _ in range(n)]
q = deque()
q.append((x, y))
il[x][y] = 0
vis[x][y] = 1
while len(q) != 0:
a, b = q.popleft()
for x_d, y_d in [[-1, 2], [-2, 1], [-2, -1], [-1, -2], [1, 2], [2, 1], [2, -1], [1, -2]]:
xx = x_d + a
yy = y_d + b
if 0 <= xx < n and 0 <= yy < m and vis[xx][yy] == 0:
q.append((xx, yy))
vis[xx][yy] = 1
il[xx][yy] = il[a][b] + 1
return il
n, m, x, y = map(int, input().split())
x -= 1
y -= 1
for i in bfs():
for j in i:
print('{:<5}'.format(j), end='')
print()
上面的vis数组也可以直接去掉,用距离数组表示标记数组。代码如下:
from collections import deque
def bfs():
# 标记数组和距离数组2合1
il = [[-1] * m for _ in range(n)]
q = deque()
q.append((x, y))
il[x][y] = 0
while len(q) != 0:
a, b = q.popleft()
for x_d, y_d in [[-1, 2], [-2, 1], [-2, -1], [-1, -2], [1, 2], [2, 1], [2, -1], [1, -2]]:
xx = x_d + a
yy = y_d + b
if 0 <= xx < n and 0 <= yy < m and il[xx][yy] == -1:
q.append((xx, yy))
il[xx][yy] = il[a][b] + 1
return il
n, m, x, y = map(int, input().split())
x -= 1
y -= 1
for i in bfs():
for j in i:
print('{:<5}'.format(j), end='')
print()