广度优先问题是机考常考题型之一。这类题型一般有独特的解题结构。
题目表述
人类通过对火星的大气进行宜居改造分析,使得火星已在理论上具备人类居住的条件,由于技术原因,无法一次性将火星大气进行改造,只能通过局部处理的方式。
假设火星待改造区域是一张二维地图,每个位置有3种取值,分别是宜居区(YES)、可改造区(NO)和死亡区(NA)。其中,
YES表示该网格已完成大气改造,
NO表示该网格未进行改造,后期可以进行改造,
NA表示死亡区,无法穿过。
初始状态下,该区域可能有多个宜居区,且每个宜居区能同时在单位太阳日向上下左右四个方向的相邻格子同时扩散,请计算这个待改造区域的网格中,可改造区能否全部变成宜居区,如果可以,则返回改造的天数;不可以则返回-1。
输入
YES YES NO
NO NO NO
NA NO YES
每个位置之间由空格进行分割,且空格内的元素只包含YES、NO、NA,不考虑非法输入的情况
输出
需改造的天数或-1
示例1
输入
YES YES NO
NO NO NO
YES NO NO
输出
2
第一天扩散后只剩下第二排最后一个和第三排最后一个未改造。第二天扩散后全部改造完成。所以改造全部区域需要两天
示例2
YES NO NO NO
NO NO NO NO
NO NO NO NO
NO NO NO NO
输出
6
按照每天向外扩散一格的方式进行填充,总共需要6天完成全部区域的改造
题目说明
关键字:局部处理,每个宜居区能同时在单位太阳日向上下左右四个方向的相邻格子同时扩散。
题意:求出改造完所有区域需要的天数。
思路:同批次一起处理,计算天数,广度优先。
解题思路及代码
解决“地图”型问题,处理好输入十分重要。
输入用二维数组进行存储。存储完输入后,需要统计YES所在位置并记录NO的数量,前者是为初始化广度优先遍历数组,后者是为判断最终是否已全部改造完成。
该题广度优先遍历的关键结构为while + for的循环嵌套方式。while用来判断是否还有宜居区未进行扩散改造,for用来完成当天进行扩散任务的宜居区的扩散。
代码如下(示例):
arr = []
q = []
m = 0
n = 0
cnt = 0 # 已改造NO的个数
def dfs(i, j):
global arr, q, cnt
if i - 1 >= 0 and arr[i - 1][j] == 'NO': # 当前位置已经改造成功
arr[i-1][j] = 'YES' # 该位置已变为yes,参与下一轮改造
cnt += 1
q.append([i - 1, j])
if j - 1 >= 0 and arr[i][j - 1] == 'NO':
arr[i][j-1] = 'YES'
cnt += 1
q.append([i, j - 1])
if i + 1 < n and arr[i + 1][j] == 'NO':
arr[i + 1][j] = 'YES'
cnt += 1
q.append([i + 1, j])
if j + 1 < n and arr[i][j + 1] == 'NO':
arr[i][j+1] = 'YES'
cnt += 1
q.append([i, j + 1])
# 把数据存入二维数组
while 1:
s = input()
if str(s) == '':
break
vec = s.split()
arr.append(vec)
m = len(arr)
n = len(arr[0])
need = 0
for i in range(m):
for j in range(n):
if arr[i][j] == 'YES':
q.append([i, j])
elif arr[i][j] == 'NO':
need += 1
day = 0
while len(q) > 0: # 还有yes
s = len(q)
for i in range(s):
now = q[0] # 当前需要处理的YES
q.pop(0) # 该位置已经处理完毕
dfs(now[0], now[1])
if len(q) > 0:
day += 1
if cnt == need:
print(day)
else:
print(-1)
总结
广度优先遍历与深度优先遍历的不同之处在于遍历方式的差异。广度优先是层层遍历的方式,所以常用于解决包含层序关系的题目。