📜  门| Sudo GATE 2021 测验 |第 54 题(1)

📅  最后修改于: 2023-12-03 15:12:45.589000             🧑  作者: Mango

门 | Sudo GATE 2021 测验 |第 54 题

题目描述:

有一个二维的 n×m 的地图,地图上的每一个位置上可能有一个门或者是一个空位置,把所有门的位置作为起点,相同的门之间可以互相到达。定义一个点的唯一编码为它的行号与列号,用一个整数对 (x,y) 来表示,其中 x 表示行号,y 表示列号。你需要找出所有门每对之间的最短距离。如果门 i 与门 j 之间无法到达,则输出 "Impossible"。

编写一个函数 get_distance_map,接收一个 n*m 大小的整数二维数组 matrix,其中 matrix[i][j] 可以取值 0 或者是 1,其中 1 表示门,0 表示空位置。函数需要返回一个大小为 C(n,2) 的二维整数数组,其中第 i 行表示门之间的距离,依次为门 1 到 门 i+1, 门 i+2, ...... ,门 n 。如果两个门之间无法到达,则用 -1 表示。

示例:

输入:

matrix = [ [1, 0, 0, 1], [1, 1, 1, 0], [0, 0, 1, 1] ]

输出:

[ [-1, 3, 2], [3, -1, 1], [2, 1, -1] ]

解释:

  1. 门 1 到自己距离为 0。
  2. 门 1 到门 2 的距离为 3。
  3. 门 1 到门 3 的距离为 2。
  4. 门 2 到自己距离为 0。
  5. 门 2 到门 3 的距离为 1。
  6. 门 3 到自己距离为 0。

如果两个门不相连,则用 -1 表示距离。

解题思路:

本题是一个典型的最短路径问题。题目要求我们找出所有门之间的最短距离,对于这种需要求出最短距离的场景,我们可以考虑使用广度优先搜索算法(BFS)来解决。

具体步骤如下:

  1. 找出所有门的位置作为起点,并标记出其编号。
  2. 针对每一个门,使用 BFS 计算出其与其它门之间的最短距离。
  3. 返回门之间的最短距离矩阵。

时间复杂度为 O(nm(n+m)),空间复杂度为 O(nm)。

参考代码如下所示:

from typing import List
from queue import Queue


def bfs(matrix: List[List[int]], start: tuple) -> List[int]:
    """使用 BFS 计算最短距离"""
    n, m = len(matrix), len(matrix[0])
    dx, dy = [-1, 0, 1, 0], [0, 1, 0, -1]  # 上右下左
    visited = [[False] * m for _ in range(n)]  # 记录是否访问过
    dist = [-1] * n * m  # 到每个点的距离

    q = Queue()
    x, y = start
    q.put((x, y))
    visited[x][y] = True
    dist[x * m + y] = 0

    while not q.empty():
        x, y = q.get()
        for i in range(4):
            nx, ny = x + dx[i], y + dy[i]
            if 0 <= nx < n and 0 <= ny < m and not visited[nx][ny]:
                if matrix[nx][ny] == 1:
                    # 找到了另一个门
                    visited[nx][ny] = True
                    dist[start[0] * m + start[1] * n] = dist[nx * m + ny] = dist[x * m + y] + 1
                elif matrix[nx][ny] == 0:
                    visited[nx][ny] = True
                    dist[nx * m + ny] = dist[x * m + y] + 1
                    q.put((nx, ny))
    return dist


def get_distance_map(matrix: List[List[int]]) -> List[List[int]]:
    n, m = len(matrix), len(matrix[0])
    # 统计门的数量
    count = 0
    for i in range(n):
        for j in range(m):
            if matrix[i][j] == 1:
                count += 1

    if count == 0:
        # 没有门
        return [[]]

    # 找出所有门的位置,并标记出其编号
    doors = []
    for i in range(n):
        for j in range(m):
            if matrix[i][j] == 1:
                count -= 1
                doors.append((i, j, len(doors)))
                if count == 0:
                    break
        else:
            continue
        break

    # 计算门之间的最短距离
    res = [[-1] * len(doors) for _ in range(len(doors))]
    for i in range(len(doors)):
        dist = bfs(matrix, doors[i][:2])
        for j in range(i + 1, len(doors)):
            res[i][j] = res[j][i] = dist[doors[j][0] * m + doors[j][1]]

    return res

注:上述代码中的 get_distance_map 函数即为本题所需的函数,函数接收一个 n*m 大小的整数二维数组 matrix,其中 matrix[i][j] 可以取值 0 或者是 1,其中 1 表示门,0 表示空位置。函数返回一个大小为 C(n,2) 的二维整数数组,其中第 i 行表示门之间的距离,依次为门 1 到 门 i+1, 门 i+2, ...... ,门 n 。如果两个门之间无法到达,则用 -1 表示。