Максимальный суммарный прямоугольник в разреженной матрице

Найти максимальный суммарный прямоугольник в матрице NxN можно выполнить в O(n^3) раз, используя 2-й алгоритм kadane, как указано в других сообщениях. Однако, если матрица разрежена, в частности O(n) ненулевые записи, может ли быть избито время O(n^3)?

Если это помогает, для текущего приложения, которое меня интересует, достаточно иметь решение, которое предполагает не более одного ненулевого значения в каждой строке и в каждом столбце матрицы. Тем не менее, в моих будущих приложениях это предположение может быть нецелесообразным (будет сохраняться только ограниченность), и в любом случае моя математическая интуиция заключается в том, что может быть хорошее решение (ы), которое просто использует разреженность и не будет далее использовать тот факт, что матрица произведение диагонали и матрицы перестановок.

Ответ 1

Да, это можно сделать лучше.

Прежде всего, подумайте о структуре данных, которая позволяет нам

  • Обновить любое одно значение базового массива 1D в O(logn) время
  • Найдите сумму максимального подмассива массива в O(1) времени

Собственно, сбалансированное двоичное дерево, которое выглядит как ниже, может выполнять эту работу. Древовидную структуру можно описать как:

  • Каждый лист node дерева представляет каждый элемент массива.
  • Если внутренний node охватывает диапазон [a, b], его левый дочерний элемент охватывает диапазон [a, c], а его правый дочерний элемент охватывает диапазон [c + 1, b], где c = floor((a + b) / 2)).
  • Корень node охватывает диапазон [1, n].

                          O
                        /   \
                      /       \
                    /           \
                  /               \
                /                   \
              O                       O
            /   \                   /   \
           /     \                 /     \
          /       \               /       \
        O           O           O           O
       / \         / \         / \         / \
     o     o     o     o     o     o     o     o
    A[1]  A[2]  A[3]  A[4]  A[5]  A[6]  A[7]  A[8]
    

К каждому node v (включая листовые узлы и внутренние узлы) прикрепляются 4 поля:

  • S[v]: сумма всех значений в диапазоне v
  • M[v]: максимальная сумма субарама в диапазоне v
  • L[v]: сумма максимального подмассива, начинающаяся с левой стороны диапазона v
  • R[v]: сумма максимального субарама, которая заканчивается в правой части диапазона v

На основе приведенных выше определений мы можем найти следующие правила обновления:

  • Для любого листа node v, S[v] = A[v], M[v] = L[v] = R[v] = max{0, A[v]}
  • Для любого внутреннего node v и его дочерних элементов l и r,
    • S[v] = S[l] + S[r]
    • M[v] = max{M[l], M[r], R[l] + L[r]}
    • L[v] = max{L[l], L[r] + S[l]}
    • R[v] = max{R[r], R[l] + S[r]}

Наконец, мы можем реализовать операции, упомянутые в начале.

  • Чтобы обновить A[i], мы можем найти соответствующий лист node в дереве и обновить поля по пути к корню, используя приведенные выше правила.
  • Максимальная сумма субарама просто M[root].

Теперь обсудим, как найти максимальный прямоугольник, используя эту структуру данных. Если мы зафиксируем верхнюю строку и нижнюю строку прямоугольника на i th и j -й строки, проблема превратится в проблему с 1D максимальным суммарным суммированием, где A[k] = sum{B[i..j, k]}. Ключевое понимание заключается в том, что при фиксированном i, если мы перечислим j в порядке возрастания, мы можем использовать приведенную выше структуру данных для поддержки базового массива 1D и быстрого поиска ответа. Псевдокод описывает идею:

result = 0
for i in (1, 2, ..., n)
    set all fields of the binary tree T to 0
    for j in (i, i + 1, ..., n)
        for any k where B[j, k] != 0
            T.update(k, A[k] + B[j, k])
        result = max{M[root], result}
return result

Предположим, что матрица содержит m ненулевые элементы, временная сложность этого алгоритма O(mn logn). В вашем случае m = O(n), поэтому временная сложность O(n^2 logn) и лучше, чем O(n^3).