309魔幻世界中的安全区计算 | 豆包Marscode Al刷题

119 阅读3分钟

问题描述

小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)