Подтвердить что ты не робот

Поиск максимальной размерной подматрицы всех 1 в матрице с 1 и 0

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

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

4b9b3361

Ответ 1

Решение 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, где каждый элемент представляет число 1s выше и включает его, вплоть до первого 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
    • Нажмите (h, i).
  • Else:
    • Пока h_cur<h_top:
      • Поместите верхнюю часть стека.
      • Проверьте, будет ли он работать лучше, т.е. (i_cur-i_pop)*h_pop > best.
    • Если h_cur>h_top
      • Нажмите (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) Нажмите (1, 0).
 i=1, C[i]=3) Нажмите (3, 1).
 i=2, C[i]=2) Pop (3, 1). Проверьте, является ли (2-1)*3=3 новым лучшим.
 Последним i popped было 1, поэтому нажмите (2, 1).
 i=3, C[i]=2) h_cur=h_top, не делайте ничего.
 i=4, C[i]=3) Нажмите (3, 4).
 i=5, C[i]=0) Pop (3, 4). Проверьте, является ли (5-4)*3=3 новым.  Поп (2, 1). Проверьте, является ли (5-1)*2=8 новым.  Поп (1, 0). Проверьте, является ли (5-0)*1=5 новым.  Конец. (Хорошо, мы должны, вероятно, добавить дополнительный термин C [cols] = 0 на конец для хорошей меры).

Ответ 2

Вот алгоритм 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 variable), когда вы нажмете нуль, а затем reset работает Всего. Это даст вам максимальную длину смежной последовательности единиц в переменной 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), основанный на динамическом программировании. Я еще не могу понять, кроме случая, когда подмассива, который вы используете, квадратная. Однако у кого-то может быть лучшая проницательность, поэтому подождите немного больше.

Ответ 3

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

case 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: оба соседства равны:       Рассматриваются три прямоугольника:

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

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

  • A [i, j].width = min (A [i + 1, j].width + 1, A [i, j + 1].width) и A [i, j].height = min (A [i, j + 1] + 1, A [i + 1, j])

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

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

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

Ответ 4

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

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

    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;
    }