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

📅  最后修改于: 2023-12-03 15:12:45.086000             🧑  作者: Mango

Sudo GATE 2020 Mock II (January 10, 2019) - Problem 24

题目描述

给你一个包含 $n$ 个门的房间棋盘。

$$ \begin{matrix} & & & & & \ & 1 & \longrightarrow & 2 & \longrightarrow & 3 \ & & & | & & \ & & & V & & \ & 4 & \longleftrightarrow & 5 & \longrightarrow & 6 \ & & & & & \ \end{matrix} $$

门可以在两个房间之间通行(如上图所示),也可以是单向的。 在任何时间只能从左上方的起始点(房间1)开始并进入所有房间。

在每个房间中,你可以决定是否开门或不开门。你可以在每个房间中最多打开一个门(无论单向或双向门)。 如果可以打开某些门,则可以通过这些门通往下一个房间。 否则,你不能进入下一个房间。

请确定是否可以穿过房间棋盘并计算出到达右下方房间(房间6)的最大可能房间数。

假设 $n$ 是偶数。

输入格式

输入包含一行,其中仅包含 $n$ - 一个偶数。

输出格式

输出在每个房间中最多可以打开一个或不打开房门时可以到达房间6的最大可能房间数。

输入样例1:
6
输出样例1:
5
输入样例2:
8
输出样例2:
7
解题思路

这是一道图论问题,可以将房间与门抽象出一个图。我们将每个房间看作图中的一个节点,将门看作节点间的边。

创建邻接矩阵

接下来,我们需要创建一个邻接矩阵来存储这个图。邻接矩阵 matrix 的大小为 $n * n$。其中 $matrix[i][j]$ 表示从第 $i$ 个点到第 $j$ 个点之间是否有边。如果有,为 $1$;否则为 $0$。

在这里给大家展示一个样例 $n=6$ 的邻接矩阵:

$$ \begin{pmatrix} 0 & 1 & 0 & 0 & 0 & 0 \ 0 & 0 & 1 & 0 & 0 & 0 \ 0 & 0 & 0 & 1 & 0 & 0 \ 0 & 0 & 0 & 0 & 1 & 0 \ 0 & 0 & 0 & 0 & 0 & 1 \ 1 & 0 & 0 & 0 & 0 & 0 \ \end{pmatrix} $$

应用拓扑排序

我们可以通过遍历拓扑排序来确定是否可以到达房间 $6$。拓扑排序的基本思想是:在有向无环图中,按照拓扑顺序遍历图的节点。对于任何具有边 $u,v$ 的节点 $u$ 和 $v$,节点 $u$ 必须在接下来的遍历中出现在节点 $v$ 之前。

具体操作如下:

  1. 初始化 $q = {1}$
  2. 初始化 $visit = {0}$,用于记录每个节点是否被访问过
  3. 通过遍历队列 $q$ 来访问节点,每次从队首取出一个节点 $u$
  4. 从 $u$ 出发,访问能够直接到达的其他节点 $v$,如果 $v$ 未被访问过,将其标记为已访问,并加入队列 $q$
  5. 重复执行步骤3-4,直到队列为空

如果某个时刻在队列 $q$ 中出现了房间 $6$,则意味着可以到达这个房间,返回这个时候的队列长度。

代码实现
import numpy as np

n = int(input())
matrix = np.zeros(shape=(n,n)) #初始化邻接矩阵

for i in range(1,n,2):
    for j in range(i+1,n+1):
        if i+1 == j or ((i//2+1) == (j//2) and (i%2) == 1 and (j%2) == 0):
            matrix[i-1][j-1] = 1 #双向门,即可从i到j也可从j到i 
            matrix[j-1][i-1] = 1 #将i和j之间连一条边

visit = [0]*n
visit[0] = 1
q = [0] #队列初始化为1
length = 1 

while len(q) > 0:
    u = q.pop(0)
    for v in range(n):
        if matrix[u][v] == 1 and visit[v] == 0:
            visit[v] = 1
            q.append(v)
            length += 1
            if v == n-1:
                print(length)
                exit()
                
print(length)

这个程序返回了两个长度,这很容易纠正。