查找给定二进制数据中的最大区域

时间:2010-09-12 21:27:08

标签: c algorithm optimization binary brute-force

我在描述用于查找二进制数据的最大矩形区域的算法时遇到问题,其中1比k更频繁地出现k次。数据总是n ^ 2位,如下所示:

例如,n = 4的数据如下所示:

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

k的值可以是1 .. j(k = 1表示0和1的数量相等)。

对于上述数据示例,对于k = 1,解决方案是:

1 0 1 0 < - 4 x'0'和4 x'1'
    0 0 1 1
   0 1 1 1
   1 1 0 1

但在这个例子中:
1 1 1 0
0 1 0 0
0 0 0 0
0 1 1 1

解决方案是:
1 1 1 0
0 1 0 0
0 0 0 0
0 1 1 1

我试过几个暴力算法,但是对于n> 20它变得太慢了。你能告诉我如何解决这个问题吗?


正如RBerteig所提出的那样 - 问题也可以这样描述:“在一个给定的方形位图中,通过某个任意过程将单元格设置为1或0,找到最大的矩形区域,其中1和0以指定的比例出现, K“。

3 个答案:

答案 0 :(得分:3)

Bruteforce在这里应该做得很好n< 100,如果正确实现:下面的解决方案具有O(n ^ 4)时间和O(n ^ 2)存储器复杂度。在现代PC上,10 ^ 8的操作应该远低于1秒(特别是考虑到每个操作都很便宜:很少添加和减少)。

一些观察

  1. 需要考虑O(n ^ 4)个子矩形,并且每个子矩形都可以作为解决方案。
  2. 如果我们可以在O(1)(恒定时间)的每个子矩形中找到1和0的数量,我们将在O(n ^ 4)时间内解决问题。
  3. 如果我们知道某个子矩形中的1的数量,我们可以找到零的数量(通过区域)。
  4. 因此,问题简化为:创建数据结构,允许在恒定时间内找到每个子矩形中的1个数

    现在,假设我们有子矩形[i0..i1]x[j0..j1]。即,它占据i0和i1之间的行以及j0和j1之间的列。让count_ones成为计算子矩形中1的数量的函数。

    这是主要观察结果:

    count_ones([i0..i1]x[j0..j1]) = count_ones([0..i1]x[0..j1]) - count_ones([0..i0 - 1]x[0..j1]) - count_ones([0..i1]x[0..j0 - 1]) + count_ones([0..i0 - 1]x[0..j0 - 1])
    

    与实际例子相同:

    AAAABBB
    AAAABBB
    CCCCDDD
    CCCCDDD
    CCCCDDD
    CCCCDDD
    

    如果我们需要在D子矩形(3x4)中找到1的数量,我们可以通过在整个矩形(A + B + C + D)中取1的数量,减去1的数量(A) + B)矩形,在(A + C)矩形中减去1的数字,在(A)矩形中添加1的数字。 (A + B + C + D) - (A + B) - (A + C) + (A) = D

    因此,对于每个sumsi,在子矩形j中包含1的1,我们需要表[0..i][0..j]
    您可以在O(n ^ 2)中创建此表,但即使是填充它的直接方式(对于每个ij迭代[0..i][0..j]区域的所有元素)也将是O( N R个4)。

    有了这张表,

    count_ones([i0..i1]x[j0..j1]) = sums[i1][j1] - sums[i0 - 1][j1] - sums[i1][j0 - 1] + sums[i0 - 1][j0 - 1]
    

    因此,达到了时间复杂度O(n ^ 4)。

答案 1 :(得分:2)

这仍然是蛮力,但您应该注意的是,您不必从头开始重新计算新的i*j矩形。相反,对于每个可能的矩形大小,您可以一次一步地在n*n网格上移动矩形,减少矩形内不再位的计数,并递增新输入矩形的位数。您可以将其与变化的矩形大小结合起来,并尝试找到移动和调整矩形大小的最佳模式。

答案 2 :(得分:0)

只是一些提示..

您可以对值施加更好的限制。要求导致条件

N1*(k+1) == S*k,其中N1是区域中的数量,S=dx*dy是其表面。 它可以以更好的形式重写:

N1/k == S/(k+1)

由于数字nn+1的最大公约数始终为1,因此N1必须是kdx*dy的倍数才是多个k+1。它大大减少了解决方案的可能空间,k越大越好(对于dx*dy,您需要使用k+1的素数除数。

现在,因为你只需要具有这种属性的最大区域的表面,从最大的区域开始并移动到较小的区域是明智的。通过尝试满足除数和边界条件的dx*dy downto n^2 k+1,你会发现解决方案非常快,比O(n ^ 4)快,因为一个特殊的原因:除了特殊构造数组的情况外,如果我们假设一个随机输入,N1区域中有S(n-dx+1)*(n-dy+1)个值的概率是表面S将随着S的减少而不断增长。 (k的较大值会使概率变小,但同时它们会使dxdy对的过滤器变得更强。

此外,这个问题:http://ioinformatics.org/locations/ioi99/contest/land/land.shtml,看起来有点类似,也许你会在他们的解决方案中找到一些想法。