【问题标题】:Maximum sum rectangle in a 2D matrix using divide and conquer使用分治法的二维矩阵中的最大和矩形
【发布时间】:2021-11-20 22:10:26
【问题描述】:

我需要实现一个最大和算法,该算法在 2D 矩阵上使用分而治之的策略。我熟悉在 O(n^6) 时间内运行的蛮力方法和在 O(n^3) 中运行的 Kadane 算法,但是如何实施分而治之的方法呢?我整天都在想这件事,什么都没有想到。为了提供上下文,蛮力解决方案是这样的:

void maxSumBruteForce() {
    vector<vector<int>> matrix = genRandomMatrix();
    int maxSum = INT_MIN;
    printMatrix(matrix);

    for (int startRow = 0; startRow < matrix.size(); ++startRow) {
        for (int startCol = 0; startCol < matrix.size(); ++startCol) {
            for (int endRow = startRow; endRow < matrix.size(); ++endRow) {
                for (int endCol = startCol; endCol < matrix.size(); ++endCol) {
                    int curSum = 0;
                    for (int row = startRow; row <= endRow; ++row) {
                        for (int col = startCol; col <= endCol; ++col) {
                            curSum += matrix[row][col];
                        }
                    }

                    if (curSum > maxSum)
                        maxSum = curSum;
                }
            }
        }
    }

    cout << "MAX SUM: " << maxSum << endl;
}

Kadane 的算法可以在这里找到:https://www.geeksforgeeks.org/maximum-sum-rectangle-in-a-2d-matrix-dp-27/

我认为解决方案将检查矩阵的四个象限,然后是中间的各种组合。

【问题讨论】:

  • 战术说明:Geeks For Geeks 几乎没有内容管理,因此您在从网站获取建议时必须小心。除非您已经知道要寻找的大部分内容,否则您可能无法区分天才的正确工作与 so wrong that they can't comprehend that they are not right 的人的搞笑咆哮之间的区别。我在 Geeks for Geeks 上看到的奇幻作品比玩 D&D 的 40 年还要狂野。
  • 我了解您的意思,但我看到多个站点证实了通过 Kadane 算法实现的解决方案。我仍然无法在这个问题上取得任何进展。
  • Kadane 可以重新表述为分而治之:personal.utdallas.edu/~daescu/maxsa.pdf
  • 使用动态编程技术可以非常有效地解决此类问题。
  • @DavidEisenstat 我已经看到这用于最大子数组问题,但我的问题是找到一个最大矩形。我真的不知道该怎么做。我也知道动态编程通常是要走的路,但有人告诉我要实现分而治之的解决方案,而不是动态编程。

标签: c++ algorithm


【解决方案1】:

改编文章的一种方法1 David Eisenstat shared in the comments 可能如下:

如果我们把矩形一分为二,

 -------------------
|         |         |
|         |         |
|   A     |    B    |
|         |         |
|         |         |
 -------------------

最大总和在A 中,或者在B 中,或者在一个矩形中,其中一部分在A 中,一部分在B 中。为了计算后者,我们从每一侧使用total_summax_summax_prefixmax_suffix,用于每个O(num_rows^2) 行边界。

        A
 ---------------
|               |
|-----row_i-----|
|               |
|<--total_sum-->|
|               |
|max_pfx--|     |
|     |--max_sfx|
|               |
|-----row_j-----|
|               |
|               |
 ---------------

那么对于每个窗口row_irow_j,从A和B我们有:

total_sum_AB = total_sum_A + total_sum_B
max_prefix_AB = max(max_prefix_A, total_sum_A + max_prefix_B)
max_suffix_AB = max(max_suffix_B, max_suffix_A + total_sum_B)
max_sum_AB = max(max_sum_A, max_sum_B, max_suffix_A + max_prefix_B)

Python 代码:

def g(M, num_rows, l, r):
  dp = [[None] * num_rows for _ in range(num_rows)]

  if l == r:
    for i in range(num_rows):
      dp[i][i] = [M[i][l], M[i][l], M[i][l], M[i][l]]

      for j in range(i+1, num_rows):
        dp[i][j] = [M[j][l] + dp[i][j-1][0], M[j][l] + dp[i][j-1][1], M[j][l] + dp[i][j-1][2], M[j][l] + dp[i][j-1][3]]

    return dp

  mid = l + (r - l) // 2

  dp_l = g(M, num_rows, l, mid)
  dp_r = g(M, num_rows, mid + 1, r)

  for i in range(num_rows):
    for j in range(i, num_rows):
      [total_sum_l, max_sum_l, max_pfx_l, max_sfx_l] = dp_l[i][j]
      [total_sum_r, max_sum_r, max_pfx_r, max_sfx_r] = dp_r[i][j]

      total_sum = total_sum_l + total_sum_r
      max_pfx = max(max_pfx_l, total_sum_l + max_pfx_r)
      max_sfx = max(max_sfx_r, total_sum_r + max_sfx_l)
      max_sum = max(max_sum_l, max_sum_r, max_sfx_l + max_pfx_r)

      dp[i][j] = [total_sum, max_sum, max_pfx, max_sfx]

  return dp


def f(M):
  num_rows = len(M)

  dp = g(M, num_rows, 0, len(M[0]) - 1)

  best = -float('inf')

  for i in range(num_rows):
    for j in range(i, num_rows):
      [total_sum, max_sum, max_pfx, max_sfx] = dp[i][j]
      best = max(best, max_sum, max_pfx, max_sfx)

  return best

输出:

M = [
  [ 1,  2, -1, -4,-20],
  [-8, -3,  4,  2,  1],
  [ 3,  8, 10,  1,  3],
  [-4, -1,  1,  7, -6]
]

print(f(M)) # 29

"""
  [ 1,  2, -1, -4,-20],
       -----------
  [-8,| -3,  4,  2,|  1],
  [ 3,|  8, 10,  1,|  3],
  [-4,| -1,  1,  7,| -6]
       -----------
"""

1分而治之:线性时间的最大子数组(Ovidiu Daescu 和 Shane St. Luce,德克萨斯大学达拉斯分校计算机科学系)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 2019-03-13
    • 2011-06-18
    • 2014-08-24
    相关资源
    最近更新 更多