📜  门| Sudo GATE 2021的测验|问题20(1)

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

Sudo GATE 2021的测验 - 问题20

本次测验将涵盖以下内容:

  • 程序设计基础
  • 数据结构
  • 算法
  • 计算机组成原理
问题20

这是一道关于门电路的问题。

给定一个 $N \times M$ 的门电路网格,其中 $1$ 表示门关闭,$0$ 表示门打开。

我们从网格的左上角 $(R_1, C_1)$ 出发,到达右下角 $(R_2, C_2)$ 时,如果网格上的门全部是打开的,那么我们就成功了。否则我们就失败了。

请你编写一个程序,判断是否能够成功通过这个电路网格。如果能够成功,则输出 "Yes",否则输出 "No"。

输入格式

第一行包含两个整数 $N$ 和 $M$,表示网格的行数和列数。

接下来 $N$ 行,每行包含 $M$ 个整数 $0$ 或 $1$,表示电路网格。其中 $1$ 表示门关闭,$0$ 表示门打开。

接下来一行包含四个整数 $R_1$,$C_1$,$R_2$ 和 $C_2$,表示起点和终点的位置。

输出格式

如果能够成功通过这个电路网格,则输出 "Yes",否则输出 "No"。

数据范围

$2 \leq N, M \leq 100$

样例

输入样例1

5 5
0 1 0 0 0
0 1 1 1 0
0 0 1 0 0
0 1 0 1 1
1 1 0 0 0
1 1 5 5

输出样例1

Yes

输入样例2

2 2
0 1
1 0
1 1 2 2

输出样例2

No
解题思路

本题可以使用广度优先搜索(BFS)来解决,以下是BFS的代码模板。

from collections import deque

def bfs(start):
    q = deque()
    q.append(start)
    while q:
        node = q.popleft()
        # do something
        for nei in neighbors(node):
            if nei not in visited:
                visited.add(nei)
                q.append(nei)
  • 初始化队列
  • 将起点入队列
  • 当队列不为空时,取出队列头部的元素,并进行相应的操作
  • 将头部元素的未被访问过的邻居入队

我们可以用这个模板来解决本题。

具体来说,我们首先使用 BFS 遍历整个有向图,然后在 BFS 的过程中,记录所有可以在终点位置之前到达的节点。最后,我们检查从起点位置有没有去往这些节点的边,以及这些节点到终点位置的边是否全部是开着的。

代码
from collections import deque

n, m = map(int, input().split())

grid = [list(map(int, input().split())) for _ in range(n)]

r1, c1, r2, c2 = map(int, input().split())

dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]


def is_valid(x, y):
    return 0 <= x < n and 0 <= y < m


def is_all_open(visited):
    for x, y in visited:
        if grid[x][y] == 1:
            return False
    return True


def bfs(start: tuple[int, int], end: tuple[int, int]) -> bool:
    if start == end:
        return True

    q = deque()
    q.append(start)
    visited = set(start)
    while q:
        x, y = q.popleft()
        for i in range(4):
            nx, ny = x + dx[i], y + dy[i]
            if not is_valid(nx, ny) or (nx, ny) in visited:
                continue
            if grid[nx][ny] == 1:
                continue
            visited.add((nx, ny))
            q.append((nx, ny))
            if (nx, ny) == end and is_all_open(visited):
                return True
    return False


if bfs((r1 - 1, c1 - 1), (r2 - 1, c2 - 1)):
    print('Yes')
else:
    print('No')
时间复杂度

对于该题而言,BFS 的时间复杂度为 $O(NM)$,其中 $N$ 为网格的行数,$M$ 为网格的列数。因为我们最多只需要遍历网格中的每个点一次。