📌  相关文章
📜  门| Sudo GATE 2020 Mock II(2019年1月10日)|问题28(1)

📅  最后修改于: 2023-12-03 14:58:33.355000             🧑  作者: Mango

题目28:门

问题描述

在一个小镇有一些房子和一扇大门。

所有的房子和大门都位于 $m$ 行 $n$ 列的矩阵 $M$ 中。

大门位于第 $i_{gate}$ 行第 $j_{gate}$ 列,用字符 $g$ 表示。

所有房子用字符 $h$ 表示。我们用 $f_i$ 表示第 $i$ 间房子在矩阵中的位置,$f_i = (x_i, y_i)$。

你的任务是找到距离大门最远的房子,并输出它到大门的曼哈顿距离。

如果从大门无法到达某个房子,请输出 $-1$。

输入格式

第一行包含三个整数 $m$, $n$, $k$,其中 $k$ 表示房子的数量。

接下来一行 $n$ 个字符,对应矩阵中第一行的字符。

接下来 $m-1$ 行,每行 $n$ 个字符,为矩阵中其余 $m-1$ 行字符。

其后 $k$ 行,每行两个整数 $x_i,y_i$,表示第 $i$ 间房子在矩阵中的位置。

矩阵中左上角的格子表示第 $1$ 行第 $1$ 列,第 $i$ 行第 $j$ 列对应的格子为 $(i,j)$,大门的位置为 $(i_{gate},j_{gate})$。$1\leq m,n,k\leq500$。

输出格式

输出距离大门最远的房子与大门的曼哈顿距离,如果没有房子能够到达,请输出 $-1$。

示例

输入:

3 4 2
g..h
....
hh..
2 2
3 3

输出:

3
分析

本题要求我们求解大门和所有房子之间的曼哈顿距离,其中距离最大的那个房子即为所求。

本题的大门和房子的位置均给定,我们可以利用广度优先搜索求解大门与每个房子之间的最短距离。

曼哈顿距离即为两点之间横纵坐标差的绝对值之和,用 $d(x_1,y_1,x_2,y_2)$ 表示点 $(x_1,y_1)$ 和 $(x_2,y_2)$ 之间的曼哈顿距离,则有:

$$d(x_1,y_1,x_2,y_2)=|x_1-x_2|+|y_1-y_2|$$

可以直接套用广度优先搜索的模板求解。

广度优先搜索的时间复杂度为 $O(mnk)$,其中 $n,m,k$ 分别为矩阵的行数、列数和房子的数量。虽然符合要求,但当矩阵较大时,耗时较长。另一种更优秀的算法是多源广度优先搜索,其时间复杂度为 $O(mn)$,相较于广度优先搜索节省了 $k$ 的数量级。在本题条件下,多源广度优先搜索可以毫无压力地通过本题。

参考代码
def bfs(m, n, gates, houses):
    q = []
    visited = [[False] * n for _ in range(m)]
    max_distance = 0
    for i, j in houses:
        # 处理无法到达的情况
        if m_distance((i, j), gates) == -1:
            return -1
        q.append((i, j, 0))
        visited[i][j] = True
    while q:
        i, j, distance = q.pop(0)
        max_distance = max(max_distance, m_distance((i, j), gates))
        for x, y in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]:
            if 0 <= x < m and 0 <= y < n and not visited[x][y]:
                visited[x][y] = True
                q.append((x, y, distance+1))
    return max_distance


def m_distance(p1, p2):
    """计算曼哈顿距离"""
    x1, y1 = p1
    x2, y2 = p2
    if (x1, y1) == (x2, y2):
        return 0
    if x1 != x2 and y1 != y2:
        return -1
    return abs(x1-x2) + abs(y1-y2)


m, n, k = map(int, input().split())
grid = [[c for c in input().strip()] for _ in range(m)]
houses = [(int(input().split()[0])-1, int(input().split()[1])-1) for _ in range(k)]
gates = (None, None)
for i in range(m):
    for j in range(n):
        if grid[i][j] == 'g':
            gates = (i, j)
            break
    if gates[0] is not None:
        break
print(bfs(m, n, gates, houses))