📜  门| GATE CS 2019 |第 32 题(1)

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

门 | GATE CS 2019 |第 32 题

题目描述

有 $n$ 扇门,每扇门可以是开或关状态。对于每扇门,都有一扇门或多扇门与之相连。给定每扇门与之相连的门的编号,编写程序确定完全打开所有门的最小操作次数。

输入格式

第一行包含一个整数 $n$,表示有 $n$ 扇门 $(1 \leq n \leq 10^5)$。

接下来 $n$ 行,第 $i$ 行包含一个整数 $m_i$,表示和第 $i$ 扇门相连的门的数量。接下来 $m_i$ 个整数,表示第 $i$ 扇门相连的门的编号 $(1 \leq m_i \leq n)$。每扇门只会在这里被列举一次。

输出格式

输出一个整数,表示完全打开所有门的最小操作次数。如果所有门都不能完全打开,输出 $-1$。

示例输入
7
2 2 3
2 4 5
2 6 7
0
1 1
1 1
1 2
示例输出
2
解释

一个可能的步骤序列如下:1) 开启门 1, 6 和 7。操作次数为 1。2) 开启门 2,3,4 和 5。操作次数为 1。

题目分析

本题可以使用广度优先搜索(BFS)算法解决。我们可以把每个门看成节点,它所连接到的所有门均可视为这个门的邻居节点。找到每个门的相邻门后,我们可以将其邻居节点塞入队列中。当我们从队列中弹出某个门时,我们将检查是否要打开这个门,如果要打开它,就将产生一次操作。

如果最终所有门都被打开了,我们将返还操作的次数,不然的话我们将返回 -1。

按照上述思路形成的python代码如下:

from collections import deque

n = int(input().strip())

graph = [[] for _ in range(n + 1)]
visited = [False] * (n + 1)
queue = deque()
count = 0

for i in range(1, n + 1):
    door = list(map(int, input().strip().split()))[1:]
    for d in door:
        graph[i].append(d)

queue.append(1)
visited[1] = True

while queue:
    u = queue.popleft()
    count += 1
    for v in graph[u]:
        if not visited[v]:
            queue.append(v)
            visited[v] = True

print(count - 1 if count == n else -1)

上述代码使用邻接列表表示节点之间的关系。时间复杂度为 $O(n+m)$,其中 $n$ 是节点数,$m$ 是边数。空间复杂度为 $O(n+m)$。