动态编程 - 最大的方块

时间:2009-11-13 01:46:30

标签: c matrix dynamic-programming

我需要在一个充满1和0的巨型文件中找到1的最大平方。我知道我必须使用动态编程。我将它存储在2D数组中。任何有关找到最大方块的算法的帮助都会很棒,谢谢!

示例输入:

1 0 1 0 1 0
1 0 1 1 1 1
0 1 1 1 1 1
0 0 1 1 1 1
1 1 1 1 1 1

答案:

1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1

到目前为止我的代码:

int Square (Sq[int x][int y]) {
   if (Sq[x][y]) == 0) {
       return 0;
   }
   else {
       return 1+MIN( Sq(X-1,Y), Sq(X,Y-1), Sq(X-1,Y-1) );
   }
}

(假设已经输入数组的值)

int main() {
    int Sq[5][6]; //5,6 = bottom right conner
    int X = Square(Sq[5][6]);
}

我如何从那里继续?

7 个答案:

答案 0 :(得分:77)

以下是解决方案的草图:

对于每个单元格,我们将保留一个计数器,使用该单元格作为左上角可以制作多大的正方形。显然,所有带0的单元格都会有0作为计数。

从右下方的单元格开始迭代并向左下方移动,然后向上一行并重复。

每次扫描都这样做:

  1. 如果单元格为0,则分配count=0
  2. 如果单元格为1并且是边缘单元格(仅限底边或右边),请指定count=1
  3. 对于所有其他单元格,请检查右侧,右下方和下方的单元格计数。取最小值并加1并将其分配给计数。保留一个全局max_count变量以跟踪到目前为止的最大数量。
  4. 在遍历矩阵结束时,max_count将具有所需的值。

    复杂性不再是遍历矩阵的成本。

    这是遍历后矩阵的样子。括号中的值是计数,即可以使用单元格左上角进行的最大正方形。

    1(1) 0(0) 1(1) 0(0) 1(1) 0(0)
    1(1) 0(0) 1(4) 1(3) 1(2) 1(1)
    0(0) 1(1) 1(3) 1(3) 1(2) 1(1)
    0(0) 0(0) 1(2) 1(2) 1(2) 1(1)
    1(1) 1(1) 1(1) 1(1) 1(1) 1(1)
    

    在Python中实现

    def max_size(mat, ZERO=0):
        """Find the largest square of ZERO's in the matrix `mat`."""
        nrows, ncols = len(mat), (len(mat[0]) if mat else 0)
        if not (nrows and ncols): return 0 # empty matrix or rows
        counts = [[0]*ncols for _ in xrange(nrows)]
        for i in reversed(xrange(nrows)):     # for each row
            assert len(mat[i]) == ncols # matrix must be rectangular
            for j in reversed(xrange(ncols)): # for each element in the row
                if mat[i][j] != ZERO:
                    counts[i][j] = (1 + min(
                        counts[i][j+1],  # east
                        counts[i+1][j],  # south
                        counts[i+1][j+1] # south-east
                        )) if i < (nrows - 1) and j < (ncols - 1) else 1 # edges
        return max(c for rows in counts for c in rows)
    

答案 1 :(得分:8)

LSBRA(X,Y)表示“最大正方形,右下角为X,Y”

伪代码:

LSBRA(X,Y):
   if (x,y) == 0:
       0
   else:
       1+MIN( LSBRA(X-1,Y), LSBRA(X,Y-1), LSBRA(X-1,Y-1) )

(对于边缘单元格,您可以跳过MIN部分,如果(x,y)不为0,则返回1。)

在“wave”中对角线穿过网格,如下所示:

    0 1 2 3 4
  +----------
0 | 1 2 3 4 5
1 | 2 3 4 5 6
2 | 3 4 5 6 7
3 | 4 5 6 7 8

或者,只要您填写边缘单元格,就可以从左到右,从上到下进行工作。

    0 1 2 3 4
  +----------
0 | 1 2 3 4 5
1 | 6 7 8 9 .
2 | . . . . .
3 | . . . . .

这样你就不会遇到以前没有计算过必要数据的计算 - 因此所有LSBRA()“调用”实际上只是你先前计算结果的表查找(因此动态编程方面)。

为什么会有效

为了在X,Y处有一个右下角的正方形,它必须包含一个较小尺寸的重叠正方形,以触及其他3个角中的每个角。换句话说,要有

XXXX
XXXX
XXXX
XXXX

你还必须......

XXX.    .XXX    ....    ....
XXX.    .XXX    XXX.    ....
XXX.    .XXX    XXX.    ....
....    ....    XXX.    ...X

只要你有3个(每个LSBRA支票),N尺寸的正方形加上当前的正方形也被“占用”,你将有一个(N + 1) - 尺寸的正方形。

答案 2 :(得分:3)

我想到的第一个算法是:

  1. '&安培;&安培;'列/行1,列/行2,如果,这就是说'&amp;&amp;'每个条目与其他列/行中相应条目之间的操作。
  2. 检查结果列,如果有任何长度为2 1,则意味着我们达到2x2平方。
  3. 下一栏有前两个结果。如果有任何长度为3 1,我们已达到3x3平方。
  4. 重复直到所有列都已使用。
  5. 从第2列开始重复1-4。
  6. 我不会向您展示实施,因为它非常简单,您的问题听起来像家庭作业。此外,有可能采用更有效的方法,因为如果输入非常大,这将变得很慢。

答案 3 :(得分:2)

让输入矩阵为M:n x m

T[i][j]是DP矩阵,其中包含方形右下角(i,j)的最大正方形边。

填写表格的一般规则:

if (M[i][j] == 1) {
  int v = min(T[i][j-1], T[i-1][j]);
  v = min(v, T[i-1][j-1]);
  T[i][j] = v + 1;
}
else 
  T[i][j] = 0;

结果方块大小是T中的最大值。

填写T[i][0]T[0][j]是微不足道的。

我不确定此算法是否可用于巨大文件, 但您不需要存储整个矩阵T ,只能存储当前行和上一行。

以下注释可以帮助解决一般想法:

  • 具有右下角(i-1,j),(i,j-1),(i-1,j-1)且尺寸为s的所有正方形都在右下角(i,j)的正方形内大小为s + 1。
  • 如果在(i,j)处有右下角的大小s + 1的正方形,那么右下角(i-1,j),(i,j-1),(i)的最大正方形的大小-1,j-1)至少是s。
  • 对面也是如此。如果在(i-1,j),(i,j-1),(i-1,j-1)处具有右下角的至少一个正方形的尺寸小于s,则具有右下角的正方形的尺寸at(i,j)不能大于s + 1.

答案 4 :(得分:1)

好的,效率最低但很简单的方法是:

  1. 选择第一项。检查是否为1,如果是,则为1x1平方。

  2. 检查下面一个,一个检查一个,如果是1,则检查第2行第2行,如果是1,2x2平方。

  3. 检查第3行col 1,col 2和col 3,加上第1行第3列,第2行第3列,如果是1,3x3。

  4. 所以基本上你一直在扩展行和col并检查其边界内的所有单元格。一旦你达到0,它就会被打破,所以你连续1点移动,然后重新开始。

  5. 在行尾,移至下一行。

  6. 直到结束。

  7. 你可能会看到那些适合while循环等的方式,以及如何使用&&来检查0,当你看到它时,你或许也会注意到它是如何被加速的起来。但正如刚才提到的另一个答案,它听起来有点像家庭作业,所以我们会把实际的代码留给你。

    祝你好运!

答案 5 :(得分:1)

这里的关键是你可以使用动态编程跟踪区域的而不是实际区域。

算法如下:

存储一个名为max-square的整数二维数组,其中索引i处的元素j表示它与i的平方大小,j是右下角。 (如果max [i,j] = 2,则表示索引i,j是大小为2 ^ 2 = 4的正方形的右下角)

对于每个索引i,j:

if 在i,j元素为0,然后将max-square i,j设置为0.

其他:

找到max-square [i - 1,j]和max-square [i,j - 1]和max-square [i - 1] [j -1]的最小。将max-square [i,j]设置为1 +最小值3.感应地,你最终会填充max-square数组。查找/或跟踪流程中的最大值,返回该值^ 2。

看看人们提出的这些解决方案: https://leetcode.com/discuss/questions/oj/maximal-square?sort=votes

答案 6 :(得分:0)

设N是2D阵列中的单元格数量。存在一种非常有效的算法来列出所有最大的空矩形。最大的空方块位于这些空矩形中的一个内部,并且一旦计算出最大空矩形的列表,就会发现它是微不足道的。可以在www.ulg.ac.be/telecom/rectangles以及源代码(未优化)中找到提出用于创建这样的列表的O(N)算法的论文。注意,存在证明(参见论文)最大空矩形的数量由N限制。因此,选择最大空方块可以在O(N)中完成,并且整个方法也是O(N)。实际上,这种方法非常快。实现很容易,因为整个代码不应超过40行C(列出所有最大空矩形的算法需要大约30行C)。