📅  最后修改于: 2023-12-03 15:28:48.546000             🧑  作者: Mango
给定一个 n 行 m 列的地图,地图中用 0 表示空地,用 1 表示障碍物。在地图中选择一个起点和一个终点,你需要求出从起点出发,最少需要经过几个障碍物才能到达终点。
输入共 n+2 行,第一行包含两个整数 n,m,表示地图的大小。
接下来 n 行,每行包含 m 个 0 或 1,表示地图。
最后一行包含四个整数 x1,y1,x2,y2,表示起点坐标为 (x1,y1),终点坐标为 (x2,y2)。地图的行和列下标都从 1 开始。
输出一个整数,表示从起点出发,最少需要经过几个障碍物才能到达终点。如果无法到达终点,输出 -1。
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
1 2 4 5
7
本题为典型的图论--最短路问题,可以使用宽度优先搜索(BFS)来解决。从起点开始寻找目标点,采用类似于树的层次遍历的方式,先遍历到的点距离源点的步数更小,因此在遍历过程中,维护一个当前点距离起点的步数变量,以及一个队列,每次将当前点入队并标记访问过,同时更新离起点的距离和是否到达终点。
具体实现过程中需要注意以下几点:
def bfs(n, m, graph, x1, y1, x2, y2):
queue = [(x1, y1, 0)] # 初始化队列,从起点出发距离为0
visited = [[False] * m for _ in range(n)] # 初始化所有点为未访问
visited[x1][y1] = True # 标记起点为已访问
while queue:
x, y, step = queue.pop(0)
for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]: # 遍历上下左右4个点
nx, ny = x+dx, y+dy
if 0 <= nx < n and 0 <= ny < m and not visited[nx][ny] and not graph[nx][ny]:
# 若该点在图内、未访问过、是空地,则进入队列并标记为已访问
visited[nx][ny] = True
queue.append((nx, ny, step+1))
if nx == x2 and ny == y2: # 若到达目标点,则返回答案
return step+1
return -1 # 若无法到达目标点,则返回-1
if __name__ == '__main__':
n, m = map(int, input().split())
graph = [list(map(int, input().split())) for _ in range(n)]
x1, y1, x2, y2 = map(int, input().split())
ans = bfs(n, m, graph, x1-1, y1-1, x2-1, y2-1) # 减1是因为题目中的行和列下标从1开始
print(ans)
BFS遍历完所有可以到达的点,时间复杂度即为图上遍历所需的时间复杂度,为 $O(nm)$。
队列中最多存储 $O(nm)$ 个点,visited数组同样需要存储所有点的访问状态,因此空间复杂度为 $O(nm)$。
总体来说,该算法的时间和空间复杂度都十分优秀,适用于解决规模较小的最短路问题。