【问题标题】:Find the set of largest contiguous rectangles to cover multiple areas [duplicate]找到一组最大的连续矩形以覆盖多个区域[重复]
【发布时间】:2011-01-15 20:11:47
【问题描述】:

我正在为游戏Dwarf Fortress 开发一个名为Quickfort 的工具。 Quickfort 将 csv/xls 格式的电子表格转换为一系列命令,供 Dwarf Fortress 执行,以便在游戏中绘制“蓝图”。

我目前正在尝试以最佳方式解决此工具 2.0 版本的区域绘图问题。

考虑以下定义二维网格的绘图命令的“蓝图”。网格中的每个单元格都应该被挖出(“d”)、引导(“c”)或不作图(“.”)。实际使用中可能存在任意数量的不同绘图命令。

. d . d c c
d d d d c c
. d d d . c
d d d d d c
. d . d d c

为了尽量减少需要发送到 Dwarf Fortress 的指令数量,我想找到一组最大的连续矩形,这些矩形可以完全覆盖或“绘制”所有可绘制的单元格。为了有效,给定矩形的所有单元格必须包含相同的命令。

这是一种比 Quickfort 1.0 更快的方法:将每个单元格单独绘制为 1x1 矩形。 This video 显示了两个版本的性能差异。

对于上面的蓝图,解决方案是这样的:

. 9 . 0 3 2
8 1 1 1 3 2
. 1 1 1 . 2
7 1 1 1 4 2
. 6 . 5 4 2

上面每个相同编号的矩形表示一个连续的矩形。最大的矩形优先于也可以在其区域中形成的较小的矩形。编号/矩形的顺序并不重要。

我的current approach 是迭代的。在每次迭代中,我构建了一个最大矩形列表,这些矩形可以通过从单元格向所有 4 个方向延伸,由每个网格的可绘制单元格形成。在将列表排序为最大之后,我从找到的最大矩形开始,将其底层单元格标记为“已绘制”,并将该矩形记录在列表中。在绘制每个矩形之前,检查其底层单元格以确保它们尚未绘制(与先前的绘图重叠)。然后我们重新开始,找到可以形成的最大剩余矩形并绘制它们,直到所有单元格都被绘制为某个矩形的一部分。

我认为这种方法比愚蠢的蛮力搜索稍微优化了一些,但我浪费了很多周期(重新)计算单元格的最大矩形并检查底层单元格的状态。

目前,这个矩形发现例程占据了该工具总运行时间的最大份额,尤其是对于大型蓝图。为了速度,我牺牲了一些准确性,只考虑单元格中的矩形,这些单元格似乎形成了一个矩形的角(使用一些并不总是正确的相邻单元格启发式方法确定)。由于这种“优化”,我当前的代码实际上并没有正确生成上述解决方案,但它已经足够接近了。

更广泛地说,我认为最大矩形优先的目标是该应用程序的“足够好”的方法。但是我观察到,如果目标是找到矩形的最小集(最少数量)以完全覆盖多个区域,则解决方案将如下所示:

. 3 . 5 6 8
1 3 4 5 6 8
. 3 4 5 . 8
2 3 4 5 7 8
. 3 . 5 7 8

第二个目标实际上代表了问题的更优化解决方案,因为更少的矩形通常意味着更少的命令发送到 Dwarf Fortress。然而,基于我有限的数学知识,这种方法让我觉得更接近 NP-Hard。

如果您想更好地了解整体策略,请观看the video;我没有解决 Quickfort 过程的其他方面,例如找到绘制所有矩形的最短光标路径。可能有解决这个问题的办法,将这些多种策略连贯地结合起来。

任何形式的帮助都将不胜感激。

【问题讨论】:

  • 你试过遗传算法吗?听起来很适合这个问题。

标签: algorithm geometry


【解决方案1】:

我找到了 San-Yuan Wu 和 Sartaj Sahni 的论文Fast Algorithms To Partition Simple Rectilinear Polygons,您可能会感兴趣。在您的示例中,带有字符“d”的区域形成一个直线多边形,带有“c”和“.”的区域也是如此。本文包括无孔简单直线多边形的算法。

如果多边形包含孔洞,则算法的运行时间为 O(n^3/2 log n),正如 JM Keil 在论文 Polygon Decomposition 第 11 页所述。

如果最小化在分割过程中引入的线段的总长度是另一个优化标准,如果多边形包含孔(第 12 页),问题就变成了 NP 完全问题。对于这些问题,存在近似算法(本文指的是具有此类算法的论文)。如果多边形不包含孔洞,则存在 O(n^4) 时间算法。

【讨论】:

  • 快速浏览一下摘要说这仅适用于“无孔”多边形。这会在这里工作吗?顺便说一句,感谢您提供了一个很棒的链接!
  • @templatetypedef:我什至对这个话题都不是很熟悉,joelpt 的问题刚刚引起了我的兴趣。但是,是的,本文中描述的算法仅适用于 hole-free 多边形。如果多边形包含孔,问题就变成了 NP 完全问题(正如论文 Polygon Decomposition 所述,我编辑了我的答案以包含本文的链接)
  • 第二篇论文确实在第 12 页上说,“如果多边形包含孔,它们表明问题变得 NP 完全”,但它们正在最小化分区过程中引入的线段的总长度(墨水总量)。
  • @Steinbitglis:你说得对,感谢您指出这一点。我将编辑我的答案。
【解决方案2】:

这不是真正的答案,但使用简单的搜索可以得到

. 1 . 2 3 3
4 1 5 2 3 3
. 1 5 2 . 6
7 1 5 2 8 6
. 1 . 2 8 6

基本上,您从左上角开始并将其用作下一个矩形的左上角,然后检查可以将其向右和向下扩展多远,然后找到剩余位的最顶部和最左侧的单元格等等。

这在某些情况下可能非常无效,但它很快,因为您不必重新计算任何东西..

【讨论】:

  • 我简单地修改了我的代码,只执行从单元格到东部和南部的连续区域搜索,结果发现性能提高了约 25%,但击键次数增加了 10-45%(不太准确)。我敢肯定,如果我重组代码以最大限度地减少重新扫描,它的性能会更高。
【解决方案3】:

在我看来,找到一组覆盖原始区域的矩形的所有解决方案都是正确的。找到一组较小的矩形更好,因为它压缩/性能更好。

所以我不建议尝试找到最佳解决方案。 (我猜这也是 NP 难的)。

为了获得更快运行的解决方案,您最初可以将矩阵平铺成 4 个单元格,如果它们相同,请尝试合并它们。之后,您可以合并 4 个组(如果它们相同)。完成后递归执行。

这不会找到最佳解决方案,但会非常快。如果您的矩阵很大,连续区域很大,那么与最佳矩阵的差异不会那么大。

【讨论】:

  • 感谢这个想法。这让我想到了一个解决方案,在每个单元格处,我们通过迭代尝试向外扩展矩形的每个边缘来扩大矩形的尺寸。我认为这类似于您的 4 细胞组想法,但允许非方形区域增长。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 2011-04-21
  • 2020-07-23
  • 2012-12-25
  • 1970-01-01
  • 2020-07-30
相关资源
最近更新 更多