矩形子阵列的最大总和

时间:2012-03-20 15:35:14

标签: arrays algorithm dynamic-programming

给定一组实数值A[1..n,1..n],我希望找到子数组

B = A[i..j,s..t]

1 <= i <= j <= n,1 <= s <= t <= n

使B中的数字总和最大化。是否可以使用动态编程解决这个问题?我和奥胡斯大学的其中一位OR教授交谈过,他不知道该怎么做,并说他很难看出它如何具有最佳的子结构质量。

但是有可能吗?如果有,怎么样?如果没有,为什么?

我已经知道一种算法在O(n^3)时间运行,通过将其减少到n(n+1)/2复杂度O(n)的子问题,但这看起来有点慢。我知道最佳算法会在Omega(n)时间内运行,但我希望动态编程可以用于在O(n^2)时间运行。

原始问题汇总

我添加了这一部分,因为我觉得有些人误解了我的问题。最初的问题是:

  1. 是否可以使用动态编程在O(n^2)时间内解决上述问题?如果有,怎么样?如果不是,为什么不呢?
  2. 其他问题:

    我在这里添加了一个新问题。稍后可能会添加更多内容:

    1. 为了使用动态编程,我需要使用解决方案来轻松解决子问题(否则这一点是没有意义的)。问题的结构是这样的,如果我们采用B = A[1..m,1..m] A[1..n,1..n]的子m < n,那么数组B的最佳解决方案最多就像A,因为同样的解决方案在A中是可行的。因此,要使用动态编程,可以合理地问:A[1..i,1..i]的最佳子阵列与A[1..i+1,1..i+1]的最佳子阵列之间的关系是什么?

2 个答案:

答案 0 :(得分:3)

一个可能有用的优化是当你可以计算得分不可能超过当前最佳时,跳过检查a,b对。

例如,一种方法是:

  1. 在每一行上运行Kadane算法(n次重复O(n)算法= O(n ^ 2))并将最大值存储在数组M中。
  2. 在O(n)时间
  3. 中计算数组M的垂直前缀和
  4. 现在,对于每个a,b对,我们可以使用我们的垂直前缀和来获得可以从此配对中获得的总和的上限,并跳过测试,如果它低于我们当前的最佳值。
  5. 如果您还在阵列M上运行Kadane算法并首先测试生成的a,b对,这可能效果最好。

    在最好的情况下(例如图像中包含黑色背景和白色矩形),这将在O(n ^ 2)中找到答案,但对于更复杂的输入,它仍然需要O(n ^ 3)

    警告:在实践中,这个技巧可能只会对一小部分输入有所帮助,因为降低了大多数人的成本......

    编辑: 一些额外的解释:

    对于第i行,M [i]包含可以从A [i..i,x..y]形式的任何高度1矩形获得的最大值。

    我们定义一个新的数组P [i](在上面的描述中称为垂直前缀和)。

    P[0]=0
    P[i+1]=M[i]+P[i]
    

    对于给定的行s和t的选择,我们可以通过计算和来快速估计可以从形式A [s..t,x..y]的任何矩形获得的最高值(M [ i]我在范围内(s,t + 1))。这实际上给了我们一个形状的值:

    ...           Row s
     ....
     .......
       ....       Row t
    

    通过从s和t之间的每一行取最佳高度1矩形而形成。

    数组P [i]是有用的,因为P [i] = sum(范围(i)中j的M [j]),因此我们可以计算和(M [i] in i的范围(s,t)在O(1)时间内+1))= P [t + 1] -P [s]。

答案 1 :(得分:1)

The Algorithmist开始,如果您有一个n×n数组,那么您可以做的最好是O(n ^ 3):

  • 首先,计算所有列的垂直前缀和(O(n ^ 2)算法)。
  • 其次,假设最大子阵列将在行a和行b之间,包括端点。只有O(n ^ 2)a,b对使得a <1。湾试试每一个。
  • 由于我们已经为所有列提供了垂直前缀和,因此可以在O(1)时间内计算列c的arr [a..b] [c]中的元素总和。这允许我们将每个列的总和想象为它是所有列中的一维数组的单个元素(具有一行和n列的一维数组)。
  • 有一个O(n)算法来计算一维数组的最大子数组,称为Kadane算法。
  • 在每个a和b组合中应用Kadane算法,得出O(n3)的总复杂度。

假设您有一个n乘2的数组,则可以将其降低到O(n ^ 2)。如上所述,关键是使用Kadane's algorithm