📜  门|门 CS 1999 |问题 23(1)

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

门|门 CS 1999 | 问题 23
问题描述

在一个$n$个点的有向图中,节点被标为$1,2,...,n$。一些节点有门,门用$1$和$0$标记,其中$0$表示门关闭,$1$表示门打开。给定一个起点和一个终点,要求找到从起点到终点的最短路径,经过的节点不能经过门为$0$的节点。若无法到达,则输出$-1$。

算法思路

考虑用广度优先搜索(BFS)来解决此问题。

首先,可以将有门的节点看作障碍物,用一个二维数组$obstacle$来记录。具体而言,如果节点$i$有门,那么$obstacle_i=1$;否则,$obstacle_i=0$。接下来,用一个$visited$数组来记录到过了哪些节点。对于每个节点$i$,$visited_i=1$表示已经访问过;否则,$visited_i=0$表示未访问过。

接下来进入BFS的主体。使用一个队列$queue$和一个距离数组$distance$来记录当前节点和到起点的距离。队列的初始状态是只有起点,距离为$0$。每次从队列中取出一个节点$i$时,枚举所有它指向(即$i->j$)的节点$j$:

  • 如果$j$已经被访问过,那么跳过$j$,去看队列中下一个节点。
  • 如果$j$没有被访问过,并且$obstacle_j=1$,那么把$j$加入到队列中,距离$distance_j$设为到$i$的距离加$1$。
  • 否则,$j$是一个门已关闭的节点,不能前往$j$。

最后,如果终点没有被访问过,那么无法到达;否则,输出$distance_{end}$。

代码实现
from collections import deque

def bfs(start, end, n, obstacles):
    visited = [0] * (n + 1)
    distance = [-1] * (n + 1)
    queue = deque([(start, 0)])
    visited[start] = 1
    distance[start] = 0
    while queue:
        curr, dist = queue.popleft()
        for next_node in range(1, n + 1):
            if curr == next_node or not obstacles[next_node]:
                continue
            if not visited[next_node]:
                visited[next_node] = 1
                distance[next_node] = dist + 1
                queue.append((next_node, dist + 1))
        if visited[end]:
            return distance[end]
    return -1
参考链接

门|门 CS 1999 | 问题 23