【问题标题】:Given many horizontal and vertical lines, how to find all the rectangles that do have any sub-rectangle inside them?给定许多水平和垂直线,如何找到其中包含任何子矩形的所有矩形?
【发布时间】:2013-04-24 15:13:38
【问题描述】:

我有许多水平和垂直线组成矩形,例如本例。

是否有一种算法或代码可以定位每个不包含另一个矩形的矩形。我的意思是,这张图片中最大的矩形不是我要找的矩形,因为它里面包含其他矩形。

我要查找的矩形必须是空的。我有每条线的起点和终点的列表,例如(a,b)到(c,d)。因此,我想要一个矩形列表 (x,y,w,h) 或等效项。

请注意,有些线与它们成直角相交,例如,此图像中最宽矩形的顶线是一条线,它有一条向下相交的垂直线。

【问题讨论】:

  • 什么列表,比如[((x1, y1), (x1, y2)), ((x1, y2), (x1, y3)), ((x1, y1), (x1, y3)), ...]
  • 只需从任何白点用泛洪填充方法绘制您的区域。每个有 4 个角的区域都是所需的矩形。
  • 它不是位图图像,我只有水平和垂直线的列表。没有洪水填充。不知道 y1, y2, y3 增加的列表是什么意思,我只需要一个矩形列表作为结果,但是它的表示。
  • 对所有 x_i 进行排序并用整数索引对其进行枚举,对 y_i 执行相同操作。现在你有整数坐标!在位图上绘制所有线条。现在可以使用 Flood-fill。

标签: algorithm rectangles


【解决方案1】:

这类问题在很大程度上由一些标准的Computational Geometry 算法来回答。对于这个特殊问题,我可以想到一个vertical sweep line 算法。

假设一个矩形由一对点(p1, p2) 表示,其中p1 是左上角,p2 是右下角。并且一个点有两个属性(可以访问为p.xp.y)。

这是算法。

  1. 对所有点对进行排序 - O(n log n)
  2. 初始化一个名为sweep line status 的列表。这将保存到目前为止遇到的所有矩形,即alive。还要初始化另一个名为event queue 的列表,其中包含即将发生的事件。这个event queue 当前包含所有矩形的起点。
  3. 处理事件,从event queue 中的第一个元素开始。
    • 如果事件是start point,则将该矩形添加到sweep line status(按y坐标排序)(在O(log n)时间)并将其右下角添加到event queue的适当的位置(按点排序)(再次在O(log n)时间)。当您将其添加到sweep line status 时,您只需要检查该点是否位于sweep line status 中它正上方的活动矩形中。如果它确实位于内部,则这不是您的矩形,否则,请将其添加到所需矩形列表中。
    • 如果事件是结束点,只需从sweep line status中删除对应的矩形即可。

运行时间(对于 n 个矩形):

  • 排序需要O(n log n)
  • 事件数 = 2*n = O(n)
  • 每个事件都需要 O(log n) 时间(对于 event queuesweep line status 中的插入。所以总数是 O(n log n)

因此,O(n log n)

更多详情请参考Bentley–Ottmann algorithm。以上只是对此的简单修改。

编辑:

刚刚意识到输入是线段,但由于它们总是形成矩形(根据问题),预处理的线性遍历可以将它们转换为矩形(点对)形式。

【讨论】:

    【解决方案2】:

    我认为不同的表示将帮助您解决问题。例如,考虑大矩形(末端没有块)。有四个唯一的 x 和 y 坐标,对它们进行排序和索引。从图形上看,它看起来像这样:

    如果坐标(x_i, y_j)上有一个矩形的角,把它放在一个矩阵中,如下所示:

    __|_1__2__3__4_
    1 | x  x  0  x
    2 | x  x  0  0
    3 | 0  x  x  x
    4 | x  x  x  x
    

    现在根据定义,真实空间中的矩形是矩阵坐标上的矩形。例如,(3,2) (3,4) (4,4), (4,3) 处有一个矩形,但它不是“基础”矩形,因为它包含一个子矩形 (3,3) (3,4), (4,4), (4,3)。这里很容易看到递归算法,为了提高速度,请使用记忆化来防止重复计算。

    【讨论】:

      【解决方案3】:

      A sweep-line algorithm...

      所需结构:

      • V = 一组垂直线,按 x 坐标排序。

      • H = 一组水平线的所有起点和终点(并让每个点保持对线的引用)并按 x 坐标排序。

      • CH = 当前条水平线的一组(最初为空)排序(按 y 坐标)。

      • CR = 当前 个矩形的排序(按 y 坐标)集合。这些矩形将具有左、上和下坐标,但还没有右坐标。请注意,此集合中不会有重叠。

      算法:

      从左到右同时处理V和H。

      每当遇到水平线的起点时,将该线添加到 CH。

      每当遇到水平线的末端时,将其从 CH 中删除。

      每当遇到垂直线时:

      • 从 CR 中删除与线重叠的所有矩形。对于所有移除的矩形,如果它完全包含在行内,将其大小与迄今为止最好的矩形进行比较,如果更好则存储。

      • 在行的底部和顶部之间迭代处理CH中的每个元素,如下所示:

        • 在 CR 中添加一个矩形,最后处理的点为底部,当前点为顶部,垂直线的 y 坐标为左侧。

      完成。

      注意:

      当水平起点或终点或垂直线的 x 坐标相等时,必须保持以下顺序:

      x of horizontal start < x of vertical line < x of horizontal finish
      

      否则你会错过矩形。

      【讨论】:

        【解决方案4】:

        您的所有线都平行于 x 轴或 y 轴吗?或者,你所有的线都是平行的还是垂直的?

        从您给出的示例中,我假设您的所有线都平行于 x 或 y 轴。在这种情况下,您的行将是 [(a,b), (a,d)] 或 [(a,b), (c,b)]。

        无论如何,首要任务是找到角落。这是两条垂直线相交的点的集合。

        第二个任务是检测矩形。对于每一对角,您可以检查它们是否形成矩形。

        第三个任务是查找一个矩形内部是否有任何矩形。

        对于第一个任务,您需要将线条分成两组:垂直和水平。在那之后排序一组。前任。根据 x 轴坐标对垂直线进行排序。然后你可以把所有的水平线,做一个二分查找,找到所有的相交点。

        对于第二个任务,考虑每一对角并查看其他两个角是否存在。如果是,则查看是否有连接所有这四个角的线。如果是,你有一个矩形。

        对于第三个任务,将所有矩形放在一个区间树中。之后你可以检查两个矩形是否重叠。

        【讨论】:

        • @Dukeling 谢谢!所以我的答案仍然成立。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-07-23
        • 2010-12-07
        • 1970-01-01
        • 1970-01-01
        • 2014-06-09
        • 1970-01-01
        • 2016-12-30
        相关资源
        最近更新 更多