带正方形的网格的最小精确覆盖;额外削减

时间:2015-06-13 12:24:31

标签: algorithm linear-programming integer-programming

此问题出现在challenge中,但由于它现在已关闭,因此可以询问它。

问题(不是这个问题本身,这只是背景信息)可以像这样直观地描述,借用他们自己的形象:

cover squares

我选择以最佳方式解决它。那可能(对于决策变量)是NP完全问题(它当然在NP中,并且它闻起来像一个确切的封面,虽然我还没有证明一般的确切覆盖问题可以减少到它),但这很好,它只需要在实践中快速,不一定在最坏的情况下。在这个问题的背景下,我对任何近似算法都不感兴趣,除非它们提供削减。

有一个明显的ILP模型:生成所有可能的正方形(如果它只覆盖存在的网格单元格,则可以使用正方形),为每个正方形引入二进制变量x_i,指示我们是否使用它或不,那么

minimize sum x_i

subject to:
1) x_i is an integer
2) 0 ≤ x_i ≤ 1
3) for every cell c
       (sum[j | c ϵ square_j] x_j) = 1

约束3表示每个细胞只被覆盖一次。约束1和2使x_i成为二进制。最小的解决方案为原始问题提供了最佳解决方案。

这种线性松弛(即忽略约束1)是不太合适的,但是它做了这样的事情(这是一个6x6网格,左上角缺失):

fractional solution

这里选择了13个方格"一半" (给出6.5的客观值),大小(所以你可以更容易找到它们)

  • 1 of 4x4
  • 3 of 3x3
  • 6x2x2
  • 3 of 1x1

此实例的最佳解决方案的目标值为8,例如:

integer solution

线性放松是不太合适的,但我并不完全满意。差距有时超过10%,有时会导致整数阶段非常缓慢。

在实际问题出现的地方,是否有额外的限制,我可以添加(懒惰)作为削减,以改善分数解决方案?

我已经尝试过该问题的替代配方来寻找切割,例如,如果我们选择"左上角"而不是选择正方形。和#34;右下角",然后匹配形成覆盖所有细胞的非重叠方块?然后在每个类似反斜杠的对角线#34;上,必须有匹配数量的左上角和右下角。但这并没有帮助,因为如果我们选择正方形,那么无论如何,这种情况总是正确的,也是在分数解决方案中。

我也尝试了一些关于重叠的推理,例如,如果两个正方形明显重叠,它们的总和不得大于1,并且可以通过添加完全包含在重叠区域中的所有正方形来改善。但是这种约束不如所有细胞只被覆盖一次的约束力强。

我已经尝试过总面积的推理(因为,总覆盖面积必须等于单元格数量),但是已经通过约束保证每个单元格必须覆盖一次,根据总面积来说明只允许更多的自由。

我也尝试用方形数字(每个方格的面积,正方形)和方形数字的差异做一些事情,但这并没有结束任何有用的东西。

5 个答案:

答案 0 :(得分:6)

我使用branch and price方法对类似问题产生了良好效果(ITA' s Strawberry Fields;向下滚动)。这是my code,其中(缺少评论)可能只是一个零知识证据,我知道我在说什么。它比商业解算器(我不会命名)快几个数量级。

关键是分支策略。而不是直接分支x_i变量,这可能是你的解算器正在做的事情,而是分支更高层次的决策。我用于Strawberry Fields的那个是决定两个细胞是否会被同一个方块覆盖。如果你针对分数解决方案最关注的对,那么解决方案的结构似乎设置得相当快。

不幸的是,我无法就如何将其编程到现有的整数程序求解器中提供建议。对于Strawberry Fields,我选择了自定义所有内容,主要是因为我想,但部分是因为我在运行中生成列,使用累积网格行和网格列总和来快速评估矩形。

答案 1 :(得分:3)

目标函数值的约束

每当目标函数值是非整数时 - 例如,因为在分数解中你有一个奇数个0.5重量的正方形 - 你可以直接在目标函数上添加一个切割""强制它到下一个更高的积分值:例如,在你的示例小数解包含13个方格,每个方格的权重为0.5,总目标函数值为6.5,你可以添加约束,即所有x_i> = 7的总和

更一般的削减

这导致了一个更通用的规则,只要你有一个分数解决方案就可以使用,其中一些C的单元格被完全覆盖了#34;通过具有非整数总重量w的正方形的子集S。通过"完全覆盖",我的意思是S中的方块每个都具有非零权重,并且对于C中的每个单元格总共提供1的总权重,并且不与C外的任何单元格重叠。您可以找到这些通过为每个单元创建具有顶点的图形以及在两个顶点之间的边缘(每个顶点被(部分地)覆盖在分数解中的相同正方形)时,可以容易地创建图形的子集:该图的每个连通分量是(最小的)这样的子集。

给定具有如上所述的一些精确覆盖的单元子集C和正方形子集S的分数解,令T为仅与C中的单元重叠的所有正方形的集合(显然T是S的超集)。我们知道,LP子问题的任何最优解X只包括单元的子集C(以及候选正方形的相关子集T)必须具有与S相同的总权重,因为如果它没有这将与最优性相矛盾原始LP的分数解决方案:您可以用X替换S并获得更好的解决方案。

现在,原始问题有两套解决方案(其中任何一个都可能是空的):那些没有方形覆盖C中的单元格和C外部单元格的解决方案,以及至少有一些解决方案广场呢。我们希望禁止第一类中具有总权重的解决方案综合报道(W)。设U是与C中至少一个单元重叠的所有正方形的集合,以及C外的至少一个单元格。我们可以通过添加约束来实现这一点

Sum_{square_i in T}(x_i) + RoundUp(w) * Sum_{square_j in U}(x_j) >= RoundUp(w)

通过RoundUp(w)将第二项乘以LHS的效果是,如果在解决方案中包含覆盖C中的单元格和其他单元格的单个正方形,则约束有效地进行。远&#34 ;.这是必要的,因为S和C没有告诉我们关于原始问题的这些解决方案,因此我们无法将它们排除在外。请注意,此约束将禁止包含方形子集S的原始解法,因为在此解决方案中,U中的每个方格必须具有权重0。

没有灵丹妙药

第二种方法比第一种方法更强大,因为它可能发生,例如,图形包含两个组件,每个组件具有奇数个方块,所有组件都具有权重0.5:这意味着存在总体而言偶数个正方形,意味着整体目标函数值是积分的,从而防止了在目标函数上增加切割的可能性。但即使一次又一次地应用这些切割并不能保证最终找到可行的解决方案:作为一个具体的例子,任何时候网格本身是水平和/或垂直对称的,但可以被不对称的正方形组覆盖然后它可以很容易地被那组正方形的水平和/或垂直翻转版本所覆盖 - 更令人讨厌的是,任何"仿射组合"这两个正方形集合(即,通过权重总和为1的任意组合)。一般来说,可能有许多同样好的可行解决方案,我在这里描述的切口无法阻止LP求解器返回包含"叠加"在所有k个中,所有方块的权重均为1 / k。

[2015年7月7日编辑]

光明的一面!

虽然,正如我上面提到的那样,没有办法让LP求解器去隔离"一个特殊的可行覆盖来自分数"叠加"有几个对称的最优​​覆盖,有一个好消息:如果你确实得到了这样的叠加,它实际上很容易从中恢复一个最佳,可行的覆盖。你需要做的就是贪婪地挑选非零重量的正方形,每次都会划掉任何与你刚刚挑选的正方形重叠的正方形。如果解决方案是我所描述的叠加,这保证会起作用,同样重要的是:如果此过程适用于分数解决方案(也就是说,如果最终重复这个贪婪的步骤覆盖所有细胞)然后你得到的解决方案必须是最佳的! (假设它不是:让X是LP求解器返回的最优分数解,让F成为你贪婪地从中提取的可行解,让y成为F中任意方的最小权重。注意F中的每个方格对每个单元的覆盖值贡献至少y;因此,由于F假设是次优的,从F中每个方格的权重减去y并将X中的所有其他权重缩放1 /(1-y) )将给出另一个(可能是分数)较低权重的解决方案,与X的最优性相矛盾。)

证明任何分数解决方案(i)在"覆盖图表中都有一些成分是非常有用的。非整体总重量,或(ii)由这样的叠加组成:这意味着你可以继续使用我的"一般"削减,直到你得到一个叠加,然后你可以贪婪地解决。但就目前而言,这两个类别之外可能存在分数解决方案。

答案 2 :(得分:1)

Dynamic programming: choose a cell (any cell will do), compute all valid squares that cover it (that is, that only cover the current cell and other cells in the grid). For each such square, recursively get the minimum coverage value for the remaining area (grid minus the square), and then choose the minimum value from those (the result is that value + 1). To make things faster, try to choose a cell which has the fewest valid covering square in each level of the recursion (thus reducing the number of recursive calls in each level).

Simple really.

答案 3 :(得分:1)

我会使用A*之类的搜索来查找解决方案。重要的是要注意 A * 就像贪婪 最佳优先搜索,因为它可以使用启发式引导自己。假设你有一个正确的启发式,它会在合理的时间内找到接近最优(~0.95)的解决方案。

enter image description here

示例解决方案使用18个块而不是19个,如示例所示。除了启发式之外,您还可以使用一些预计算来提高算法效率。例如,我计算了我称之为每个位置的自由梯度。例如,您的初始地图成为一个阶段:

enter image description here

您可以拥有自己的启发式,可以同样好或甚至更好。我之所以使用它只是因为我觉得它很简单。阶段数字具有以下含义:数字越高 - 它越有可能出现在一个大盒子里(你可以得出更多限制,但这是一个开始)。

阶段值是4个酒窖自动化规则的总和。

enter image description here

例如左上角

cell(x,y) := min(cell(x,y-1) ?? 0, cell(x-1,y) ?? 0, cell(x-1,y-1) ?? 0) + 1
  

?? operator被称为null-coalescing运算符。如果操作数不为null,则返回左侧操作数;否则它会返回右手操作数。

此外,您可以通过删除从预计算和每个阶段获得的已知解决方案来减少所需的计算工作。在这种情况下,状态0:

enter image description here

算法本身会重复:

  1. 订购单元格并获取最高
  2. 订购自动化规则结果并采取最高
  3. 找到琐碎的截止日期
  4. enter image description here enter image description here

    如果你想为更大的网格获得更快的结果,那么一种相当直接的方法是将预计算扩展到编译模板。之后,您可以进行模板缩减。

    例如,你可以有一个模板(左上角部分)

    --+++
    +-+++
    +++++
    

    您可以生成它的哈希并将其添加到值为4的hashmap / dictionary(意味着它将至少需要4个矩形来覆盖+)。然后你有5x3范围和相同的哈希,你知道它是一个微不足道的截止成本4。

    与计算接近恒定速度的哈希相比,比较更快的原因是比较需要花费大量时间。

    或者,有一种方法可以催眠我们实际上正在寻找的是什么类型的解决方案。使用Wolfram Mathematica函数FindMinimum它将看起来像以下几行:

    FindMinimum[{
      a + b + c + d + e + f + g, 
      (a 1^2 + b 2^2 + c 3^2 + d 4^2 + e 5^2 + f 6^2 + g 7^2) == 119 &&
      a >= 0 && b >= 0 && c >= 0 && d >= 0 && e >= 0 && f >= 0 && g >= 0 &&
      a \[Element] Integers &&
      b \[Element] Integers &&
      c \[Element] Integers &&
      d \[Element] Integers &&
      e \[Element] Integers &&
      f \[Element] Integers &&
      g \[Element] Integers
    }, {a,b,c,d,e,f,g}]
    

    这是基于我们拥有12x12网格和119个单元格的假设,它将为我们提供使用网格大小计数的最佳解决方案。

    可悲的是wolfram alpha搜索引擎不会解释这一点,也许将来可能会这样。

答案 4 :(得分:0)

除了没有重叠的约束之外,如何使用约束使得正方形的总面积等于要覆盖的总面积?这应该比检查双重覆盖约束更快。