📜  门| GATE-CS-2015(套装1)|问题 3(1)

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

门 - GATE-CS-2015(套装1)- 问题 3

这是GATE-CS-2015(套装1)中第三个编程问题 - 门(Gate)。本篇介绍如何理解和解决该问题。

问题概述

门是用一个正方形的连通区域来表示的。每一条边都被标注为 open(开放)或 close(关闭)。门可以被表示为一个网格图,其中水平边是从左到右的,垂直边是从上到下的。边缘的门无法通过(也被认为是关闭的),但是门可以通过内部区域 。一个门被认为是 open 的,当且仅当有一个从门的左边到门的右边的 open 路径。

实现门的数据结构及功能,使其能够处理以下操作:

  1. makeUnion(N) - 建立一个 N x N 的门的二维网格结构。
  2. isOpen(i, j) - 如果单元格 (i, j) 在 open 路径上则返回 true。
  3. openDoor(i, j) - 将单元格 (i, j) 标记为 open。
  4. isConnected() - 如果门的任何部分从左到右是连通的,则返回 true。
解决方案
初始结构

考虑到问题主要是关于开门、是否通道、连通性,可以使用一个类来处理门的问题。首先,我们可以定义一个门类,以及表示网格图的 class Cell。Cell 类将处理每个单元格(i,j),并记录它是否已被打开。

class Door:
    n = None
    cells = []
    toproot = None
    bottomroot = None
    connected = False

    class Cell:
        isOpen = False

Door 类需要三个实例属性:n(门的大小,即 n x n),cell(存储门中的所有 Cell 对象的列表),connected(代表左右是否连通)。 在 MakeUnion 和 OpenDoor 操作之后,该类可以将nxn大小的门格建立。

连通问题

对于任何一个门,仅当从首位只存在 connectedTo 一个对象时,该门才是连通的。因此,可以为每个 Cell 对象添加一个 connectedTo 成员。connectedTo 可能是 None、Cell 对象中的任何一个单元格的引用。如果两个单元格之间的边缘状态为 "open",那么它们之间会有双向连接。

首先,我们定义了一个 Cell 类,并在 Door 类中追加此类。在 Cell 初始化时,我们设置 connectedTo 为其自身。然后,通过将 connectedTo 设为左侧的单元格,来将共享边缘的单元格和相邻 Cell 对象建立连接。如果这些边缘是 "open" 的,那么我们更新当前单元格的 connectedTo 和其相邻单元格的 connectedTo。重复此操作,以获取右侧的相邻单元格。最终,如果两个端点是连通的(即从首到尾有且只有一个 connected 节点),则 Gate 是被认为是连接的。

代码实现

代码实现有两个原始操作:makeUnion 和 openDoor。makeUnion 实现如下:

def makeUnion(self, n):
    self.n = n
    self.cells = [Door.Cell() for i in range(n*n)]
    self.toproot = self.Cell()
    self.bottomroot = self.Cell()

    self.toproot.connectedTo = self.bottomroot
    for i in range(n):
        self.cells[i].connectedTo = self.toproot
        self.cells[n*(n-1)+i].connectedTo = self.bottomroot

    for i in range(n-1):
        for j in range(n-1):
            self.cells[n*i+j].right = self.cells[n*i+j+1]
            self.cells[n*i+j+1].left = self.cells[n*i+j]
            self.cells[n*i+j].bottom = self.cells[n*(i+1)+j]
            self.cells[n*(i+1)+j].top = self.cells[n*i+j]

接着,我们实现 openDoor 操作:

def openDoor(self, i, j):
    cell = self.cells[self.n*i+j]
    cell.isOpen = True
    if j > 0 and self.cells[self.n*i+j-1].isOpen:
        self.union(cell, self.cells[self.n*i+j-1])
    if i > 0 and self.cells[self.n*(i-1)+j].isOpen:
        self.union(cell, self.cells[self.n*(i-1)+j])
    if j < self.n-1 and self.cells[self.n*i+j+1].isOpen:
        self.union(cell, self.cells[self.n*i+j+1])
    if i < self.n-1 and self.cells[self.n*(i+1)+j].isOpen:
        self.union(cell, self.cells[self.n*(i+1)+j])

最后,我们实现 Utils.findRoot 函数和 Door.connected 函数。

class Utils:
    @staticmethod
    def findRoot(p):
        while p.connectedTo != p:
            p.connectedTo = p.connectedTo.connectedTo
            p = p.connectedTo
        return p

def isConnected(self):
    return Utils.findRoot(self.toproot) == Utils.findRoot(self.bottomroot)

综上,我们现在已经可以通过构造门的内部图,以及通过 makeUnionopenDoor 操作来处理 "open" 和 "close" 的状态,并通过检查 left 和 right 关联成果,检测左右连接问题。

总结

门的问题涉及到“开”和“关”单元格,以及如何处理相邻单元格之间的状态。通过建立 connectedTo 属性,最终能够检测到门的一个重要特征——左右连通性。

希望通过本篇文章能够帮助您理解和解决 GATE-CS-2015(套装1)中第三个编程问题——门。