问题描述
小F被神秘力量带入了一个魔幻世界,这里危机四伏。为了在异世界中生存,小F需要找到安全区。异世界可以被表示为一个大小为 n x m 的二维数组,每个格子的值代表该位置的危险程度。
小F的能力值为 X,当某个格子的危险程度小于等于 X 时,这个格子是安全的。如果多个安全的格子相邻(上下左右连通),它们可以构成一个安全区。你需要帮助小F计算出一共有多少个安全区。
问题分析
该问题是将单个接壤的安全格子合并为安全区,再统计相离的安全区一共有多少个。题目中的接壤是上下左右相邻,不包括斜上下方。由于题目给的数组并未体现格子的安全情况,我们需要先对该数组进行遍历处理成能体现安全情况的数组:遍历数组,当格子数值小于等于小F能力X时,将该位置数值置为1;否则置为0。因此,数组中值为1的格子就是安全区,而值为0的格子就是危险区。
接下来需要对连续接壤的1区域进行统计。若是显示数组人工进行计数,得出结果是很容易的;但是计算机并不能这样做。如何把不在同一个安全区的格子区分出来是主要问题。我的主要的思路是遍历数组,当检测到有格子为1时计数加1,同时将该格子所在安全区内的所有格子置0,这样就可以防止计数重复,最终得到1区域的个数,即是安全区个数。
对于将某个值为1格子所在安全区全部格子置0,可以应用图论里深度遍历的方式:将所有格子视为节点,安全区内接壤关系视为边,从任意一个节点A开始,将该节点标记为已检测,下一个随机检测一个与A相邻的节点B,若B已检测就返回A,否则以B开始又重复以上步骤,直到B无未检测的相邻节点,再由B退回A。反复执行以上步骤,能对一个连通图进行遍历。由于值为0的格子并不是该图的节点,所以可以遍历一个值为1的安全区所有格子。在程序上,采用递归函数实现深度遍历:deep(i, j, A)中i,j是检测坐标,A为地图数组。若检测该坐标数值为0时,函数中断返回;若为1时,将该位置值置0,然后将坐标向上、下、左、右移动递归并调用函数,便能时间对安全区格子的遍历并清0。
def deep(i, j, A):
n = len(A)
m = len(A[0])
A[i][j] = 0
if i > 0 and A[i-1][j] == 1:
deep(i-1, j, A)
if i < n-1 and A[i+1][j] == 1:
deep(i+1, j, A)
if j > 0 and A[i][j-1] == 1:
deep(i, j-1, A)
if j < m-1 and A[i][j+1] == 1:
deep(i, j+1, A)
return
def solution(n: int, m: int, X: int, a: list[list[int]]) -> int:
# write code here
mar = a
for i in range(n):
for j in range(m):
if a[i][j] <= X:
mar[i][j] = 1
else:
mar[i][j] = 0
count = 0
for i in range(n):
for j in range(m):
if mar[i][j] == 0:
continue
else:
deep(i, j, mar)
count += 1
return count # return value is a placeholder
if __name__ == '__main__':
print(solution(3, 3, 4, [[2, 3, 3], [3, 3, 3], [3, 3, 3]]) == 1)
print(solution(2, 2, 5, [[6, 6], [6, 4]]) == 1)
print(solution(3, 3, 3, [[1, 2, 2], [2, 3, 3], [3, 4, 5]]) == 1)