📜  门| GATE-CS-2009 |第 49 题(1)

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

这是一道来自GATE-CS-2009的题目。本题考察了对于离散数学中关于图的知识的理解,同时要求程序员使用基本的图算法完成题目要求。

题目描述

有一个城市的地图,给定城市地图上的道路和门。每个门都有一个密钥,一个密钥可以打开一些门,但并不是每个门都需要一个密钥才能打开。假设城市地图的建造者保证了以下三个条件:

  • 在城市地图上,任意两个区域间最多只有一条道路相连,且没有环。

  • 每个门都只控制一条道路,并且可以由同一个密钥打开。

  • 每个门可以打开某些门,但是不能打开自己控制的门。

现在给定一把起始的钥匙和一个目标门,要求求出最少需要经过多少道门才能到达目标门,若无法到达,则返回-1。

函数签名:def minDoorsToCross(cityMap: Dict[str, List[str]], fromDoor: str, toDoor: str) -> int:

其中,cityMap是城市地图,是一个字典,每个键代表一个门,对应该门所控制的那条道路的终点,值为一个包含若干门名称串的列表,代表可以通过使用当前门打开这些门。

例如,样例输入为:

{
    "door1": ["room1", "door2"],
    "door2": ["door1", "room2"],
    "room1": ["door1"],
    "room2": ["door2"]
}

则代表门door1控制道路连接着room1和door2,门door2控制道路连接着door1和room2。

fromDoor和toDoor分别为起始门和目标门。

题解

本题要求求出从起始门到目标门的最少经过门的数量,可以考虑使用广度优先搜索(BFS)算法。以下为大致思路:

  1. 初始化队列,将起始门的名称加入队列中,将当前序列长设为0。

  2. 对于当前队列中的所有门(该门称为当前门),将可以通过当前门打开的门的名称加入队列中,对于队列中不含有这些新的门的,将它们加入队列中,同时,记录这些新添加的门被加入队列时的当前序列长度。

  3. 对于刚刚被加入队列的门,记录其当前序列长度,若成功到达目标门,则返回门的序列长度。

  4. 若队列为空,且没有找到目标门,则返回-1。

代码片段(Python):

from typing import Dict, List
from collections import deque

def minDoorsToCross(cityMap: Dict[str, List[str]], fromDoor: str, toDoor: str) -> int:
    doors = deque([(fromDoor, 0)]) # 初始化队列,记录当前门和序列长度
    visited = set([fromDoor]) # 记录已经遍历过的门
    while doors:
        door, steps = doors.popleft()
        for next_door in cityMap[door]:
            if next_door == toDoor:
                return steps + 1
            if next_door not in visited:
                doors.append((next_door, steps + 1))
                visited.add(next_door)
    return -1
总结

本道题要求求最短路径,使用广度优先搜索算法可以很快解决问题。在编写代码时,需要注意记录每个门的路径长度等信息,同时应该注意去重等问题,以避免死循环等错误。