Нахождение максимального размера подматрицы всех 1 в матрице, имеющей 1 и 0 - PullRequest
18 голосов
/ 27 сентября 2010

Предположим, вам дано растровое изображение mXn, представленное массивом M [1..m, 1 .. n], все записи которого равны 0 или 1. Блок все-один - это подрешетка вида M [i.. i0, j .. j0], в котором каждый бит равен 1. Опишите и проанализируйте эффективный алгоритм, чтобы найти единичный блок в M с максимальной площадью

Я пытаюсь найти решение для динамического программирования,Но мой рекурсивный алгоритм выполняется за O (n ^ n) времени, и даже после запоминания я не могу думать о его снижении ниже O (n ^ 4).Может кто-нибудь помочь мне найти более эффективное решение?

Ответы [ 4 ]

24 голосов
/ 28 сентября 2010

Решение O (N) (число элементов):

A
1 1 0 0 1 0
0 1 1 1 1 1
1 1 1 1 1 0
0 0 1 1 0 0 

Генерирует массив C, где каждый элемент представляет число, равное 1 с, включая его, вплоть до первого 0.

C
1 1 0 0 1 0
0 2 1 1 2 1
1 3 2 2 3 0
0 0 3 3 0 0 

Мы хотим найти строку R и левый, правый индексы l, r, которые максимизируют (r-l+1)*min(C[R][l..r]).Вот алгоритм проверки каждой строки за O (cols):

Поддерживает стек пар (h, i), где C[R][i-1] < h ≤ C[R][i].В любой позиции cur у нас должно быть h=min(C[R][i..cur]) для всех пар (h, i) в стеке.

Для каждого элемента:

  • Если h_cur>h_top
    • Push (h, i).
  • Остальное:
    • Пока h_cur<h_top:
      • Сложите вершину стека.
      • Проверьте, не станет ли он новым лучшим, т.е. (i_cur-i_pop)*h_pop > best.
    • Если h_cur>h_top
      • Push (h, i_lastpopped).

Пример этого в исполнении для третьего ряда в нашем примере:

  i =0      1      2      3      4      5
C[i]=1      3      2      2      3      0
                                 (3, 4)
 S=         (3, 1) (2, 1) (2, 1) (2, 1)
     (1, 0) (1, 0) (1, 0) (1, 0) (1, 0)    
     (0,-1) (0,-1) (0,-1) (0,-1) (0,-1) (0,-1) 

i=0, C[i]=1) Push (1, 0).
i=1, C[i]=3) Push (3, 1).
i=2, C[i]=2) Pop (3, 1).Проверьте, является ли (2-1)*3=3 новым лучшим.
Последний i был равен 1, поэтому нажмите (2, 1).
i=3, C[i]=2) h_cur=h_top, поэтому ничего не делайте.
i=4, C[i]=3) Нажмите(3, 4).
i=5, C[i]=0) Поп (3, 4).Проверьте, является ли (5-4)*3=3 новым лучшим.
Pop (2, 1).Проверьте, является ли (5-1)*2=8 новым лучшим.
Pop (1, 0).Проверьте, является ли (5-0)*1=5 новым лучшим.
Конец.(Хорошо, нам, вероятно, следует добавить дополнительный термин C [cols] = 0 в конце для хорошей меры).

9 голосов
/ 27 сентября 2010

Вот алгоритм O(numCols*numLines^2). Пусть S[i][j] = sum of the first i elements of column j.

Я буду работать алгоритм на этом примере:

M
1 1 0 0 1 0
0 1 1 1 0 1
1 1 1 1 0 0
0 0 1 1 0 0 

У нас есть:

S
1 1 0 0 1 0
1 2 1 1 1 1
2 3 2 2 1 1 
2 3 3 3 1 1

Теперь рассмотрим задачу нахождения максимального подмассива всех единиц в одномерном массиве. Это можно решить с помощью этого простого алгоритма:

append 0 to the end of your array
max = 0, temp = 0
for i = 1 to array.size do
  if array[i] = 1 then
    ++temp
  else
    if temp > max then
      max = temp
    temp = 0

Например, если у вас есть этот 1d массив:

1 2 3 4 5 6
1 1 0 1 1 1

вы бы сделали это:

Первое добавление 0:

1 2 3 4 5 6 7
1 1 0 1 1 1 0

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

Теперь вы можете использовать этот подалгоритм, чтобы найти решение вашей проблемы. Прежде всего добавьте столбец 0 к вашей матрице. Затем вычислите S.

Тогда:

max = 0
for i = 1 to M.numLines do
  for j = i to M.numLines do
    temp = 0
    for k = 1 to M.numCols do
      if S[j][k] - S[i-1][k] = j - i + 1 then
        temp += j - i + 1
      else
        if temp > max then
          max = temp
        temp = 0

По сути, для каждой возможной высоты подмассива (имеется O(numLines^2) возможных высот) вы находите объект с максимальной площадью, имеющей эту высоту, применяя алгоритм для одномерного массива (в O(numCols)).

Рассмотрим следующую «картинку»:

   M
   1 1 0 0 1 0 0
i  0 1 1 1 0 1 0
j  1 1 1 1 0 0 0
   0 0 1 1 0 0 0

Это означает, что у нас фиксированная высота j - i + 1. Теперь возьмем все элементы матрицы, которые находятся между i и j включительно:

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

Обратите внимание, что это похоже на одномерную проблему. Давайте сложим столбцы и посмотрим, что мы получим:

1 2 2 2 0 1 0

Теперь задача сводится к одномерному случаю, за исключением того, что мы должны найти подпоследовательность смежных j - i + 1 (в данном случае 2) значений. Это означает, что каждый столбец в нашем j - i + 1 "окне" должен быть полон единиц. Мы можем проверить это эффективно, используя матрицу S.

Чтобы понять, как работает S, еще раз рассмотрим одномерный случай: пусть s[i] = sum of the first i elements of the vector a. Тогда какова сумма подпоследовательности a[i..j]? Это сумма всех элементов до a[j] включительно, минус сумма всех элементов до a[i-1] включительно, что означает s[j] - s[i-1]. Случай 2d работает так же, за исключением того, что у нас есть s для каждого столбца.

Надеюсь, это понятно, если у вас есть еще вопросы, пожалуйста, задавайте.

Я не знаю, подходит ли это вам, но я думаю, что есть также алгоритм O(numLines*numCols), основанный на динамическом программировании. Я пока не могу понять, за исключением случая, когда искомый вами массив является квадратным. У кого-то может быть лучшее понимание, поэтому подождите немного больше.

1 голос
/ 15 июля 2014

Определить новую матрицу A, которая будет хранить в A [i, j] два значения: ширину и высоту наибольшей подматрицы с левым верхним углом в i, j, заполнить эту матрицу, начиная с нижнего правого угла, рядами снизу вверх. Вы найдете четыре случая: Выполните эти случаи, когда данная матрица при [i, j] = 1

случай 1: ни один из правых или нижних соседних элементов в исходной матрице не равен текущему, то есть: M [i, j]! = M [i + 1, j] и M [i, j] ! = M [i, j + 1] является M исходной матрицей, в этом случае значение A [i, j] равно 1x1

случай 2: соседний элемент справа равен текущему, но нижний элемент отличается, значение A [i, j] .width равно A [i + 1, j] .width + 1 и A [I, J] .height = 1

случай 3: соседний элемент снизу равен, но правый отличается, A [i, j] .width = 1, A [i, j] .height = A [i, j + 1]. высота + 1

вариант 4: оба соседа равны: Три прямоугольника считаются:

  1. A [I, J] .width = А [I, J + 1] .width + 1; A [I, J] .height = 1;

  2. A [I, J] .height = А [I + 1, J] .height + 1; а [I, J] .width = 1;

  3. A [i, j] .width = min (A [i + 1, j] .width + 1, A [i, j + 1] .width) и A [i, j]. Высота = мин (A [i, j + 1] + 1, A [i + 1, j])

Считается, что объект с максимальной площадью в трех вышеупомянутых случаях представляет прямоугольник в этой позиции.

Размер наибольшей матрицы, имеющей верхний левый угол в i, j, равен A [i, j]. Width * A [i, j] .height, поэтому вы можете обновить максимальное найденное значение при вычислении A [ I, J]

нижний ряд и самый правый элемент столбца обрабатываются так, как если бы их соседи снизу и справа соответственно различались.

0 голосов
/ 12 апреля 2017

Вот реализация O (N) в C #.

Идея состоит в том, чтобы использовать динамическое программирование для построения накопленной матрицы, которая имеет размер самой большой подматрицы, включая саму текущую ячейку.

    public static int LargestSquareMatrixOfOne(int[,] original_mat)
    {
        int[,] AccumulatedMatrix = new int[original_mat.GetLength(0), original_mat.GetLength(1)];
        AccumulatedMatrix[0, 0] = original_mat[0, 0];
        int biggestSize = 1;
        for (int i = 0; i < original_mat.GetLength(0); i++)
        {
            for (int j = 0; j < original_mat.GetLength(1); j++)
            {
                if (i > 0 && j > 0)
                {
                    if (original_mat[i, j] == 1)
                    {
                        AccumulatedMatrix[i, j] = Math.Min(AccumulatedMatrix[i - 1, j - 1], (Math.Min(AccumulatedMatrix[i - 1, j], AccumulatedMatrix[i, j - 1]))) + 1;
                        if (AccumulatedMatrix[i, j] > biggestSize)
                        {
                            biggestSize = AccumulatedMatrix[i, j];
                        }
                    }
                    else
                    {
                        AccumulatedMatrix[i, j] = 0;
                    }
                }
                else if ( (i > 0 && j == 0) || (j > 0 && i == 0))
                {
                    if (original_mat[i, j] == 1) { AccumulatedMatrix[i, j] = 1; }
                    else { AccumulatedMatrix[i, j] = 0; }
                }
            }
        }
        return biggestSize;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...