【问题标题】:Given a set of rectangles, find 3 bounding rectangles with the smallest area给定一组矩形,找出面积最小的 3 个边界矩形
【发布时间】:2011-06-30 14:55:19
【问题描述】:

我正在尝试使用最多 3 个区域来实现重绘区域,但想不出一种有效的方法来找到给定一组矩形的最佳区域集。

所以会有一组矩形,我需要计算最多 3 个产生最小面积的边界矩形。

黑色矩形是一组矩形,而红色矩形是产生最小可能区域的边界框(最多 3 个)。需要找出边界框的最佳组合。

【问题讨论】:

  • 因此,您正在为任意一组矩形寻找最小面积覆盖,这些矩形的元素也是矩形并且覆盖中最多有三个元素?也许看看聚类算法。
  • 它们可以重叠吗?另外,您的示例没有给出最小的总面积 (将左侧的两个分组或右侧的两个分组会产生较小的面积)
  • 对于canvas标签,实现重绘区域,因为它很慢。但我想这不是特定于 javascript 的。
  • @RPRPORO:没必要。考虑正方形是十字端点的情况,我们只允许两个红色矩形。然后有两个交叉形状的重叠矩形将给出最小的总面积,即使你计算该面积两次。
  • @RPRPORO:不,仍然不正确;想象与以前相同的场景,但另一个正方形与其他四个相距非常远 - 您仍然会与前四个重叠交叉,第三个边界矩形将围绕唯一的正方形。

标签: algorithm math area


【解决方案1】:

难道没有唯一的最小外接矩形吗?只需在所有矩形中获取最大和最小 x 和 y 坐标,然后根据这些规范制作一个矩形。

【讨论】:

  • 但那将是一个单一的边界矩形。如果最多有 3 个,则可以将其拆分并找到最小的集合,但是如何..?
  • 给定一组轴对齐的矩形,有一个唯一的最小边界矩形。你是说你也有3个边界矩形?如果是这样,您应该如何处理它们?我不明白你的问题。
  • 不,我的意思是大多数时候有 3 个边界矩形会产生更小的区域。但我需要弄清楚边界矩形的哪种组合是最好的(最小的区域)。见上图。
【解决方案2】:

这是一个相当简单的例子。这个想法是“增长”你的边界框,就像MST。我觉得这个问题类似于 MST,只是我们有多达 3 棵不相交的树,这大大增加了复杂性。

该算法大约需要 (n 选择 3)*(3*n) 步,即 O(n^4)。

  1. 给矩形编号。
  2. 选择 3 个矩形的任意组合。对于每个组合:
    1. 将三个初始边界框设置为其宽度/高度。
    2. 对于每个剩余的矩形:
      1. 找出如果将边界框添加到边界框,它将增加边界框的区域,对于所有三个。
      2. 将其添加到尺寸增加最小的框中(调整该边界框的大小)。

最初,这似乎不是最佳选择 - 在步骤 2.2 中添加剩余矩形的顺序会影响您获得的边界框大小 - 但是当您选择三个矩形的新组合作为开始时设置它应该捕获更好的配置。

【讨论】:

  • 这种方法非常有趣,尽管它没有考虑到边界矩形的数量,根据问题陈述,可以是一到三个,即可能有一种“黑色”矩形排列,其中最佳解决方案要求只有一个边界“红色”矩形。
  • 任何具有 1 个或 2 个矩形的最佳矩形排列都可以是具有 3 个相同大小的矩形的排列,因此最佳解决方案始终可以由 3 个边界矩形组成。
  • @Vanwaril 我明白你的意思,尽管创建边界矩形是有代价的。从这个角度来看,我假设最佳解决方案会用尽可能少的边界矩形来解决问题。
  • @RPRPORO 在这种情况下,如果边界矩形是可合并的,则合并它们几乎是微不足道的。
  • @Vanwaril 我明白你的意思,尽管几乎最优永远不会是最优的。 (:
【解决方案3】:

我同意之前“mu 太短”的评论。解决您的问题的一种算法可以根据每对“黑色”矩形之间距离的水平和垂直分量的乘积,将所有现有的“黑色”矩形划分为一到三个几何集群(这将为您提供每对之间形成的假设“红色”矩形的面积),然后将每个生成的簇与一个“红色”矩形绑定。

无论您选择哪种几何聚类算法来解决该问题的组成部分(下文将详细介绍),重要的是不要使用“直线”或欧几里德之间的距离将“黑色”矩形划分为聚类每对作为参数,因为您的问题涉及减少边界(“红色”)矩形的区域。正如我在上一段中提到的,您需要每对“黑色”矩形之间的距离的水平和垂直分量,以便考虑 区域一个可能的边界“红色”矩形将覆盖。

文献中有许多几何聚类算法具有不同的时空复杂度权衡,我建议您从 this Google search 开始并熟悉这些算法。或者,可以通过使用geneticsimulated annealing 算法在不使用聚类算法的情况下解决此问题,在这种情况下,将尝试各种组合的总面积和可能的边界“红色”矩形的数量,并且测量以产生最佳解决方案。

如有任何需要,请随时询问,祝您的项目好运!

【讨论】:

  • 您提供的算法不起作用。例如,如果有四个对角排列的正方形,那么您给出的算法可能会创建两个边界框——一个与内部两个配对,另一个与外部两个配对。此外,具有无限数量边界框的问题具有非常不同的复杂性——解决方案不相关。
  • @Vanwaril 我提供的算法适用于我制定的问题的轻松版本(无限边界矩形)。在您引用的示例中(“四个对角线排列的正方形”),该算法将从不绑定“内部两个”矩形,然后绑定“外部两个”,因为在步骤 2. ,列表“binary-clusters”按绑定每对“黑色”矩形产生的面积升序排序,即所有“黑色”矩形在算法到达“外部两个”矩形时已经被绑定, 因为它们将位于排序列表的末尾
  • @Vanwaril 我所陈述的问题的轻松版本具有与原始问题不同的复杂性这一事实并没有从我身上逃脱。问题的放松版本的目的是说明解决原始问题的可能方向,问题的放松版本通常在算法设计中出于教学目的而制定,并且为了制定可接受的启发式方法。
  • 算法不工作。假设对角线有 4 个正方形(编号 1 到 4),你会得到 n^2 对区域。算法可以首先选择 (2,3)。如果确实如此,那么它不会采用 (1,2) 或 (3,4),因为 2 和 3 存在于二进制集群列表中(步骤 4.1)。所以它最终会占用 (1,4)。
  • 你怎么能假设 (1,2) 在 (2,3) 之前添加? (2,3) 的面积可能较小。你也不能假设标签的顺序是正确的。
【解决方案4】:

与大多数 3 个矩形一样,一切都将始终在 x-y 轴上定向和对齐,并且没有重叠?你很幸运,有O(n<sup>2</sup>) 3 个这样的矩形集,用O(n<sup>3</sup>) 工作很容易枚举它们。鉴于您正在处理足够数量的黑色矩形以进行视觉显示,因此将它们全部枚举并挑选出最好的一个应该足够快。

首先让我们考虑一下 2 边界矩形的情况,因为它更简单。把图片投影到x轴很容易,把图片投影到y轴也很容易。这两个投影中的至少一个将具有不重叠的可见间隙。因此,我们可以列举划分为两个矩形的可能方法,首先将所有黑色矩形投影到 x 轴上的线段,寻找间隙,并为每个间隙重建我们得到的哪对边界框。然后用 y 轴重复该过程。我们会得到所有的。

现在 3 个边界矩形的情况类似。事实证明,给定 3 个沿 x-y 轴定向的非重叠矩形,x 投影或 y 投影必须有一个可见的间隙。所以我们可以像以前一样做同样的过程,但不是仅仅构造一对边界框,我们尝试构造一个边界框,然后使用相同的算法将另一个边界框分成两个。

(顺便说一句,您很幸运,您只想要 3。这种方法在 4 个边界矩形的情况下会失效。因为这样可能有 4 个边界矩形,使得 x 投影和 y 投影都没有任何可见的间隙。)

那么我们如何取 n 个黑色矩形,将它们投影到一个轴(比如说 x 轴),然后寻找边界矩形的集合?您只需对它们进行排序,构建最大重叠间隔,然后找到差距。像这样:

function find_right_boundaries_of_x_gaps (rectangles) {
  var ordered_rect = rectangles.sort(function (r1, r2) { return r1.x1 <=> r2.x2 });
  var gaps = [];
  var max_right = ordered_rect[0].x2;
  for (var i = 0; i < ordered_rect.length; i++) {
    if (max_right < ordered_rect[i].x1) {
      gaps.push(max_right);
    }
    if (max_right < ordered_rect[i].x2) {
      max_right = ordered_rect[i].x2;
    }
  }
  return gaps;
}

给定一个间隙,很容易找出每边的 2 个矩形边界框。 (如果你有有序的矩形,那就更直接了。)

有了这些部分,您现在应该可以编写代码了。不幸的是,幼稚的方法让您在构建大量重复代码或构建大量大型数据结构之间做出选择。但是,如果您对闭包感到满意,则可以通过两种截然不同的方式解决这两个问题。

第一个是构造闭包,当被调用时,它会遍历你想要的各种数据结构。请参阅http://perl.plover.com/Stream/stream.html 获取灵感。这里的想法是你编写一个函数,它接受一组矩形并返回一个成对的边界框流,然后另一个函数接受一组矩形,获取成对的边界框流,并返回一个三元组流的边界框。然后有一个过滤器接收该流并找到最好的。

另一个是由内而外的。与其返回一个可以遍历可能性的函数,不如传入一个函数,遍历可能性,然后在每种可能性上调用该函数。 (所述函数也可能进行进一步的迭代。)如果您接触过 Ruby 中的块,这种方法可能对您很有意义。

如果您不熟悉闭包,不妨忽略最后几段。

【讨论】:

  • 看看上面 BlueRaja 的评论——X 或 Y 中没有必要存在间隙。
  • @Vanwaril:@louis 在评论中说不可能有任何重叠。没有重叠的要求使我声称 X 或 Y 中必须存在间隙是正确的。如果重叠是可能的,那么@BlueRaja 的例子是正确的。
  • Louis 已经纠正了这一点——他发表评论时假设重叠意味着存在更好的解决方案。
  • @Vanwaril:确实他做到了......在我发表我的帖子之后假设相反。嗯,至少我的解释非常非常明确。
猜你喜欢
  • 2011-06-02
  • 1970-01-01
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多