Algorithm 在二维块栅格中查找矩形

Algorithm 在二维块栅格中查找矩形,algorithm,grid,Algorithm,Grid,假设我有一个由块组成的网格,7x12。我们使用颜色“*”、“%”、“@”和一个空单元格“-” 1 2 3 4 5 6 7 - - - - - - - 1 - - - - - - - 2 % % - - - - - 3 % % - - - - * 4 % % - - - @ % 5 @ @ @ - - @ % 6 @ @ * * * - * 7 * * * % % % % 8 % @ @ % * * % 9 % @ % % % % % 10 * * * % % @ @ 1

假设我有一个由块组成的网格,7x12。我们使用颜色“*”、“%”、“@”和一个空单元格“-”

1 2 3 4 5 6 7
- - - - - - -  1
- - - - - - -  2
% % - - - - -  3
% % - - - - *  4 
% % - - - @ %  5
@ @ @ - - @ %  6
@ @ * * * - *  7
* * * % % % %  8 
% @ @ % * * %  9
% @ % % % % %  10
* * * % % @ @  11
* * @ @ @ @ *  12
我想在这个网格中找到一个最小尺寸的矩形,我能找到的最大的,然后再更小,直到找不到大于或等于最小尺寸的矩形

在此示例中,考虑最小大小1x4、4x1、2x2,因此1x3无效,但2x3是无效的。如果我们想要最大的矩形,我们会发现:

  • 4x1 at(4,8)
  • (3,10)处的5x1
  • 2x3 at(1,3)
  • 2x2 at(6,1)
  • 2x2 at(1,11)
  • 4x1 at(3,12)
请注意,矩形不能在彼此的空间中,它们不能重叠。例如,(4,10)处的2x2矩形没有提及,因为它将与(3,10)处的5x1矩形重叠

所有矩形都是完全有效的矩形:它们等于或大于最小尺寸,每个矩形的所有块都具有相同的颜色

我想要的是以编程方式完成这项工作。当你告诉某人在网格中查找矩形时,他会毫不犹豫地立即找到它们。问题是,我怎样才能写出一个同样的算法呢

我考虑过暴力,但我需要算法尽可能快地执行,因为它需要在有限的(移动)设备上在很短的时间内大量执行


我在网上看到了很多关于矩形的问题,但是我很惊讶这个问题还没有被问到。我想的太难了,还是从来没有人想做这样的事情?

注意:这是在假设您试图找到最大的
k
矩形的情况下运行的

我们知道,在最坏的情况下,我们必须至少查看网格中的每个节点一次。这意味着我们最好的情况下最差的演员阵容是
O(len*wid)

您的蛮力将是
O(len*len*wid*wid)
,使用“检查某一点上的矩形是
O(len*wid)
,您可以多次这样做
O(len*wid)

可能你发现情况并非如此,因为每次你找到一个矩形,你就有可能减少问题空间。我觉得“检查每个矩形”的蛮力方法将是最好的方法。不过,你可以做一些事情来加快速度

基本算法:

for(x = 1 .. wid) {
    for(y = 1 .. len) {
        Rectangle rect = biggestRectOriginatingAt(x,y);
        // process this rectangle for being added
    }
}
  • 跟踪最大的
    k
    矩形。在进行过程中,您可以搜索符合条件的矩形的周长

    Rectangle biggestRectOriginatingAt(x,y) {
        area = areaOf(smallestEligibleRectangle); // if we want the biggest k rect's, this
                                                  // returns the area of the kth biggest
                                                  // known rectangle thus far
    
        for(i = 1 .. area) {
            tempwid = i
            templen = area / i
    
            tempx = x + tempwid
            tempy = y + templen
    
            checkForRectangle(x,y,tempx,tempy); // does x,y --> tempx,tempy form a rectangle?
        }
    
    }
    
这允许您在大型搜索结束时获得较大的性能提升(如果是小型搜索,您不会获得那么多,但您不在乎,因为这是小型搜索!)

这对于更多的随机分布也不起作用

  • 另一个优化是使用绘画填充算法来查找最大的连续区域。这是
    O(len*wid)
    ,这是一个很小的成本。这将允许您搜索最可能的区域,以查找要填充的大矩形

请注意,这两种方法都没有减少最坏的情况。但是,它们确实减少了实际的预期运行时间。

分别调用输入数组的宽度和高度W和H

  • 运行以确定最大矩形,而不是仅跟踪单个最大矩形,对于W*H矩阵中的每个(x,y)位置记录,计算(一个或所有)左上角为(x,y)的最大矩形的宽度和高度,并在运行时更新这些值
  • 循环遍历此矩阵,将其中每个足够大的矩形添加到按区域排序的区域(宽度*高度)
  • 从该堆中读取条目;它们将以递减的区域顺序生成。读取每个左上角为(x,y)、宽度为w、高度为h的条目时,将矩形中包含的每个wh位置标记为wh位数组中的“已使用”。从堆中读取矩形时,必须丢弃包含“已使用”的所有矩形“正方形以避免产生重叠的矩形。只检查每个候选矩形的四条边就足够了,因为候选矩形可以与另一个矩形重叠的唯一其他方式是,如果后一个矩形完全包含在其中,这是不可能的,因为我们是按面积递减顺序读取矩形
  • 这种方法是“贪婪”的,因为如果有多种方法将纯色区域雕刻成最大的矩形,它不能保证选择最大的矩形序列。(例如,可能有几个矩形的左上角位于(10,10),面积为16:16x1、8x2、4x4、2x8、1x16。在这种情况下,一个选择可能会产生较大的“下游”矩形,但我的算法不能保证做出该选择。)如果有必要,您可以使用回溯找到这一总体最优的矩形序列,尽管我怀疑这在最坏的情况下可能会非常缓慢


    我提到的最大矩形算法是为单色矩形设计的,但是如果你不能使它适应你的多色问题,你可以在开始第2步之前为每种颜色运行一次。

    我必须为我的第一人称射击手解决一个非常类似的问题。我在输入中使用它:
    [[]
    []X][][]
    []X][X][X][X][X][X][X][X]
    [][X][X][X][X][X][][][][] []X][X][X][X][]
    []X][X][X][X][]
    [][X][[]
    [[]

    我在输出中得到:
    [[]
    […]A[…]A[…]
    []B][G][G][G][F][E][E]
    [][[G][G][G][F][][]]
    [][D][G][G][G][G][D][b][b][b][b][b][b] [][D][G][G][G][G][D][b][b][b][b][b][b] [][C][]
    [[]

    这样更好。源代码(在GNU通用公共许可证版本2下)是,被大量评论。您可能需要根据自己的需要对其进行一些调整,就像j_random_hacker建议的那样。

    我自己的解决方案是
        ****|***|***                ************
        ****|***|***                ************
        ****#####***                ----#####---
        ****#####***        vs      ****#####***
        ****#####***                ----#####---
        ****|***|***                ************