全文目录
说在前面
模板-BFS迷宫⭐
传送锚点
思路点拨
代码详解
走迷宫Ⅰ⭐
传送锚点
思路点拨
代码详解
走迷宫Ⅱ⭐
传送锚点
思路点拨
代码详解
走迷宫Ⅲ⭐
传送锚点
思路点拨
代码详解
扩散⭐⭐
传送锚点
思路点拨
代码详解
全球变暖⭐⭐⭐
传送锚点
思路点拨
代码详解
鸽了一个星期的BFS模板,小蓝肝了10小时终于写完啦!q(≧▽≦q)
看了十几份题解,调试了上百次程序,终于把原本四十行的代码,精简压缩成20行模板 \^o^/
但小蓝调试的时候,出现好多BUG,研究了几个小时才找到错误原因解决(ToT)/~~~
如果没有人指导的话,友友很可能会跟我一样,掉到BUG坑里几小时出不来
所以为了节约友友的宝贵学习时间,多腾出些时间可以出去嗨皮~(╹ڡ╹ )
小蓝把思路,代码,细节,BUG 都写在文章里了(●'◡'●)
朋友只需耐心看完下面的文章即可
祝大家成功逃出迷宫
一、参数解释:
M:map地图 G:go走过路径 q=deque():双向队列 q.popleft() 头节点从左边出队
二、详细思路:
1.前期准备,先导入数据结构双向队列deque,然后输入题目要求的一堆参数。
2.初始化,创建双向队列,同时赋初值:迷宫开始坐标(0,0)。
3.模拟队列,x,y分别代表队列里出队结点的x坐标,和y坐标。
4.设置结束条件,遍历到迷宫出口(n-1,m-1),打印步数,打印走过的路径。
5.下一步路,遍历可以走的四个方向,得到下一个坐标(a,b)。
6.判断合理,判断坐标是否越界,是否之前遍历过。
7.迭代赋值:判断合理就进行标记,然后添加到队列最后,路径表上增加此刻的方向。
三、细节注意:
代码模板很细节,稍不注意就会出现BUG!小蓝作为三个坑都踩过的过来人,
来跟大家数数一共有哪些题目里的大坑(ง •_•)ง(没说到的BUG欢迎评论区一起交流)
第一个坑:为什么要用双向队列deque,列表list不可以吗?
答:用列表模拟队列,运行速度较慢,答题会超时,得不了满分。
而从collections导入deque运行速度较快,程序不会超时,可以得满分。
第二个坑:q=deque([(0,0)])怎么这么多的括号?都是啥意思?
([(0,0)])像个三明治,先外面套一层deque()函数小括号,
然后里面夹一层列表中括号[ ],最后再加一层代表坐标点小括号().
第三个坑:遍历四个方向也啥要注意的?
for i,j,k in [(1,0,'D'),(0,-1,'L'),(0,1,'R'),(-1,0,'U')]:
小蓝调试半天才发现这个错误,为了避免友友掉进同样的坑,小蓝温馨提醒一下要看题目条件:“如果有多条长度相同的最短路径,选择在此表示方法下字典序最小的一个。”
遍历顺序按字典序 D→L→R→U,也就是下↓左←右→上↑。
#BFS-迷宫模板
from collections import deque
n,m=map(int,input().split())
M=[[int(i) for i in input()] for j in range(n)]
G=[['']*m for i in range(n)]
q=deque([(0,0)])
while q:
x,y=q.popleft()
if x==n-1 and y==m-1:
print(len(G[-1][-1]))
print(G[-1][-1])
break
for i,j,k in [(1,0,'D'),(0,-1,'L'),(0,1,'R'),(-1,0,'U')]:
a,b=x+i,y+j
if 0<=a
010000
000100
001001
110000
下面这道题就是模板的经典例题,简直是为模板量身定做的ヾ(≧▽≦*)o
假如考场上碰到,别人想个半小时,你直接套个BFS模板,5分钟直接轻松拿捏✪ ω ✪
小蓝建议先自己敲一遍模板,然后稍微改改几个地方,应该就AC了(๑•̀ㅂ•́)و✧
#BFS-迷宫
from collections import deque
n,m=30,50
M=[[int(i) for i in input()] for j in range(n)]
G=[['']*m for i in range(n)]
q=deque([(0,0)])
while q:
x,y=q.popleft()
if x==n-1 and y==m-1:
print(G[-1][-1])
break
for i,j,k in [(1,0,'D'),(0,-1,'L'),(0,1,'R'),(-1,0,'U')]:
a,b=x+i,y+j
if 0<=a
上面的两题都是求最小路径方向(●'◡'●)
下面两题换个问法:求最小走格子次数(●ˇ∀ˇ●)
需要更改模板里的一些参数
q=deque([(x1-1,y1-1,0)]) 加一个0代表遍历次数。
x,y,z=q.popleft() 从队列取出来一个结点分为三部分,分别是x坐标,y坐标,和遍历次数。
q.append([a,b,z+1]) 注意迭代时遍历次数z+1。
#BFS-走迷宫Ⅱ
from collections import deque
n,m=map(int,input().split())
M=[list(map(int,input().split())) for i in range(n)]
x1,y1,x2,y2=map(int,input().split())
q=deque([(x1-1,y1-1,0)])
while q:
x,y,z=q.popleft()
if x==x2-1 and y==y2-1:
print(z)
break
for i,j in [[1,0],[-1,0],[0,1],[0,-1]]:
a,b=x+i,y+j
if 0<=a
下面来到验证题,主要检测上一题的掌握情况~
自己先做一下,学会了上一题很简单,换汤不换药,改改参数就AC了~
#BFS-走迷宫Ⅲ
from collections import deque
n,m=map(int,input().split())
M=[[i for i in input()] for i in range(n)]
q=deque([(0,0,0)])
while q:
x,y,z=q.popleft()
if x==n-1 and y==m-1:
print(z+1)
break
for i,j in [[1,0],[-1,0],[0,1],[0,-1]]:
a,b=x+i,y+j
if 0<=a
前三道迷宫题,只是BFS新手入门题,算是餐前小吃,开开胃~
现在上一道正菜,前年国赛的填空题:扩散。
主要用到两个数据结构:集合,双向队列。
选取集合容器来存储是因为它速度快,选取双向队列还是因为它速度快,
反正速度快就对了,大约半分钟就能跑完φ(* ̄0 ̄)
而如果选取列表可能要跑几分钟,估计考试的时候心态就崩了(っ °Д °;)っ(反正我会崩)
下面简单讲一下思路:
先将小蓝画布上有的4个黑点初始化,存到标记集合V和双向队列q里。
然后开始BFS搜索,如果循环2020次,就结束打印黑格子个数。
遍历四个方向,没标记,增加标记并加入队列。黑格子计数器+1.
#BFS-扩散
from collections import deque #导入双向队列
V={(0,0),(2020,11),(11,14),(2000,2000)} #V:visited标记集合
q=deque([(0,0,0),(2020,11,0),(11,14,0),(2000,2000,0)]) #q:deque双向队列
cnt=4 #初始黑格数
while q: #队列非空
x,y,z=q.popleft() #(0,0,0)
if z==2020: #终止条件
print(cnt) #print(20312088)
break #结束循环
for i,j in [[1,0],[-1,0],[0,1],[0,-1]]: #遍历四周
a,b=x+i,y+j #取新坐标
if (a,b) not in V: #没有标记
V.add((a,b)) #增加标记
q.append((a,b,z+1)) #加入队列
cnt+=1 #黑格子+1
最后一道三星省赛真题,挑战大BOSS了 !(╯‵□′)╯嘟嘟炸弹!•••*~●
总体思路:(≧∀≦)ゞ
从问题出发,题目问:“多少个岛屿会被全部淹没?”
先判断全部淹没的条件:当前格子是是'#',上下左右四个格子都是'.'的岛屿。
基本思路:φ(* ̄0 ̄)
二重循环遍历每一个坐标点,如果遇到岛屿,就进行BFS搜索,满足条件统计相加。
注意细节:(~ ̄▽ ̄)~
因为岛屿是一整个连通块,所以要一块一块地遍历。
(岛屿是指连在一起的###,不是单独的一个岛#)
#BFS-全球变暖
from collections import deque
n=int(input())
M=[[i for i in input()]for j in range(n)]
vis=[[0]*n for i in range(n)] #标记列表
flag=True #淹没标志
def bfs(x,y):
global flag
q=deque([(x,y)]) #初始化开始遍历的坐标
while q:
x,y=q.popleft()
if M[x][y+1]=='#' and M[x][y-1]=='#' and M[x+1][y]=='#' and M[x-1][y]=='#':
flag=False #如果格子的四个方向有岛屿,中间的高地不会被淹没
for i,j in [(0,1),(0,-1),(1,0),(-1,0)]:
a,b=x+i,y+j
if vis[a][b]==0 and M[a][b]=='#':
vis[a][b]=1 #标记岛屿遍历过了
q.append((a,b)) #遍历下一个岛屿
ans=0
for i in range(n): #遍历每一个格子
for j in range(n):
if vis[i][j]==0 and M[i][j]=='#':
flag=True #设置淹没标志
bfs(i,j) #搜索这个格子,判断是否需要更改淹没标志
if flag==True: #如果淹没标志不变
ans+=1 #被淹岛屿数量加1
print(ans)
'''
样例输入:
7
.......
.##....
.##....
....##.
..####.
...###.
.......
样例输出:
1
'''