Аспект динамического программирования в алгоритме Кадане

Initialize:
    max_so_far = 0
    max_ending_here = 0

Loop for each element of the array
   (a) max_ending_here = max_ending_here + a[i]
   (b) if(max_ending_here < 0)
         max_ending_here = 0
   (c) if(max_so_far < max_ending_here)
          max_so_far = max_ending_here
 return max_so_far

Может ли кто-нибудь помочь мне понять оптимальную подструктуру и проблему перекрытия (хлеб с маслом DP) в вышеуказанном алгоритме?


person Bhavish Agarwal    schedule 01.05.2013    source источник
comment
Алгоритм Кадане жадный, IIRC.   -  person nhahtdh    schedule 01.05.2013
comment
+1, я сам с этим борюсь. Я не могу решить, считается ли это DP или нет: у нас есть оптимальная подструктура, но нет пересекающихся подзадач. Однако я видел, что это обозначено как DP, но, строго говоря, я бы сказал, что это не так.   -  person IVlad    schedule 01.05.2013
comment
Не могу представить, что у кого-то такой же вопрос, как у меня;)   -  person Eric Z    schedule 17.10.2015
comment
Алгоритм Кадане жадный ?. Это слишком далеко от моего понимания. Отличительной чертой жадного алгоритма является то, что в конце алгоритма фактическое решение, которым в данном случае является подмассив, который достигает максимальной суммы, должно было быть вычислено явно, поскольку выбор, сделанный жадным алгоритмом, может зависеть от сделанного выбора. пока, но не о будущих вариантах или всех решениях подзадачи, цитируемых из статьи в Википедии о жадном алгоритме < / а>.   -  person burnabyRails    schedule 22.10.2020
comment
Но в том-то и дело, что алгоритм Кадане не зависит от всех решений подзадач. На каждом этапе он подбирает локальный оптимум.   -  person IVlad    schedule 23.10.2020
comment
@IVlad, окончательный ответ, данный в алгоритме Кадане, действительно зависит от всех решений подзадач, где каждая подзадача состоит в том, чтобы найти максимальную сумму массива, который заканчивается определенным индексом. Окончательный ответ - это максимум всех ответов на подзадачи.   -  person burnabyRails    schedule 23.10.2020
comment
@burnabyRails, который не превращает алгоритм в алгоритм DP. То же самое можно сказать и обо всех жадных алгоритмах: алгоритм Дейкстры зависит, в конце концов, и от всех решений подзадач. Если вы так расширите определение, оно будет применяться и к любому жадному алгоритму, и оно потеряет свое предназначение.   -  person IVlad    schedule 26.10.2020
comment
@IVlad, я не думаю, что то же самое можно сказать обо всех жадных алгоритмах. Можете ли вы показать, как можно классифицировать классический жадный алгоритм, алгоритм Крускала, как DP?   -  person burnabyRails    schedule 27.10.2020
comment
@burnabyRails Я не знаю, правда ли, но поскольку вы можете реализовать что-либо рекурсивно, а затем применить аналогичную логику к тому, что я использовал для Dijkstra, я бы поспорил, что это возможно. В любом случае, действительно ли изменится наша дискуссия, если я заменю всех жадных [...] на других жадных [...]?   -  person IVlad    schedule 27.10.2020
comment
@burnabyRails учитывает возведение в степень возведения в квадрат там, где вы обычно делаете что-то вроде t = pow(x, n/2); return t*t;. Если я вместо этого сделаю return pow(x,n/2)*pow(x,n/2), будет ли это DP или я просто глупый, если не сохраню возвращаемое значение рекурсивного вызова?   -  person IVlad    schedule 27.10.2020
comment
@IVlad, если хотите задать вопрос, задайте его.   -  person burnabyRails    schedule 27.10.2020


Ответы (2)


Согласно этому определению перекрывающихся подзадач рекурсивная формулировка алгоритма Кадане (f[i] = max(f[i - 1] + a[i], a[i])) не демонстрирует это свойство. Каждая подзадача будет вычисляться только один раз в наивной рекурсивной реализации.

Однако он демонстрирует оптимальную подструктуру в соответствии с его определением, которое здесь: мы используем решение меньших подзадач, чтобы найти решение данной проблемы (f[i] использует f[i - 1]).

Рассмотрим определение динамического программирования, которое здесь:

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

Идея динамического программирования довольно проста. В общем, чтобы решить данную проблему, нам нужно решить разные части проблемы (подзадачи), а затем объединить решения подзадач для достижения общего решения. Часто при использовании более наивного метода многие подзадачи генерируются и решаются много раз. Подход динамического программирования стремится решить каждую подзадачу только один раз, что сокращает количество вычислений.

Это оставляет место для интерпретации относительно того, может ли алгоритм Кадана считаться алгоритмом DP: он решает проблему, разбивая ее на более простые подзадачи, но его основной рекурсивный подход не генерирует перекрывающиеся подзадачи, для чего предназначен DP. обрабатывать эффективно - так что это выведет его за рамки специализации DP.

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

Поэтому я бы сказал, что это не алгоритм DP, а просто жадный и / или рекурсивный, в зависимости от реализации. Я бы назвал его жадным с алгоритмической точки зрения по причинам, перечисленным выше, но объективно я бы счел и другие интерпретации столь же верными.

person IVlad    schedule 01.05.2013
comment
Интересно также, что в нем задействованы всего два элемента хранения. Это снова делает его менее похожим на типичный алгоритм DP. Знаете ли вы какие-либо другие алгоритмы, которые считаются DP с таким небольшим объемом памяти? - person Peter de Rivaz; 02.05.2013
comment
@PeterdeRivaz - повторение Фибоначчи будет учитываться: оно имеет оптимальную подструктуру и перекрывающиеся подзадачи, а также может быть реализовано с O(1) памятью. - person IVlad; 02.05.2013
comment
comment
Я не уверен, о чем вы говорите. Я дал ссылки на определения из литературы, есть ли у вас опубликованные научные или учебные материалы, которые противоречат тому, что я сказал? Другие люди, говорящие разные вещи, на самом деле не являются контраргументом, если они не обращаются конкретно к моим аргументам. - person IVlad; 23.10.2020

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

Выявление подзадач и повторяющихся отношений

Представьте, что у нас есть массив a, из которого мы хотим получить максимальный подмассив. Чтобы определить максимальный подмассив, который заканчивается индексом i, выполняется следующее рекурсивное отношение:

max_subarray_to(i) = max(max_subarray_to(i - 1) + a[i], a[i])

Чтобы получить максимальный подмассив a, нам нужно вычислить max_subarray_to() для каждого индекса i в a, а затем взять из него max():

max_subarray = max( for i=1 to n max_subarray_to(i) )

Пример

Теперь предположим, что у нас есть массив [10, -12, 11, 9], из которого мы хотим получить максимальный подмассив. Это будет работа, необходимая для запуска алгоритма Кадане:

result = max(max_subarray_to(0), max_subarray_to(1), max_subarray_to(2), max_subarray_to(3))

max_subarray_to(0) = 10  # base case
max_subarray_to(1) = max(max_subarray_to(0) + (-12), -12)
max_subarray_to(2) = max(max_subarray_to(1) + 11, 11)
max_subarray_to(3) = max(max_subarray_to(2) + 9, 49)

Как видите, max_subarray_to() оценивается дважды для каждого i, кроме последнего индекса 3, что показывает, что алгоритм Кадана действительно имеет перекрывающиеся подзадачи.

Алгоритм Кадана обычно реализуется с использованием подхода DP снизу вверх, чтобы воспользоваться преимуществами перекрывающихся подзадач и вычислить каждую подзадачу только один раз, следовательно, превратив ее в O (n).

person arauter    schedule 23.10.2020
comment
Алгоритм Дейкстры также можно записать рекурсивно, если вы действительно этого хотите (см., Например: Хотяtoverflow.com/dsa/dijkstra-shortest-path-recursive.html - я уверен, что кто-то более опытный, чем я, сможет придумать рекурсивную формулу за меньшее время, чем я готов потратить на нее) . Теперь подумайте о том, чтобы найти самый длинный путь из всех кратчайших путей, начиная с исходного узла: это потребует взятия максимума dijkstra (node_1), dijkstra (node_2) и т. Д. . Так это будет DP? - person IVlad; 27.10.2020
comment
Если вы сделаете это таким образом, вы можете заставить любую проблему быть DP, но мне кажется противоречащим духу определения DP делать как можно больше в одной функции только для того, чтобы заставить рекурсивные вызовы генерировать перекрывающиеся подзадачи. Рассмотрим, например, f (i) = f (i-1) + 1, g (i) = max (g (i-1), f (i)). Это DP? f (i) вычисляет f (i-1), а также g (i-1). Да, это подходит под определение. Но это беспорядок, и вы виноваты в таком злоупотреблении рекурсией. f сам по себе не является DP, и вы также можете рассматривать вычисление f как отдельную проблему. - person IVlad; 27.10.2020
comment
@IVlad, статья в Википедии об алгоритме Дейкстры классифицирует алгоритм Дейкстры как динамическое программирование. Конечно, алгоритм Кадане широко известен как динамическое программирование (как и жадный алгоритм). - person burnabyRails; 27.10.2020
comment
@burnabyRails, эта классификация отмечена как спорная даже в Википедии. CLRS (первая ссылка на вики-странице) классифицирует его как жадный. - person IVlad; 27.10.2020
comment
@IVlad, вы сделали несколько очень хороших замечаний относительно принуждения проблемы к DP для извлечения перекрывающихся подзадач. Я понимаю, почему это можно аргументировать в пользу моего ответа здесь и почему ваш ответ кажется более правильным. Спасибо за ответ. - person arauter; 27.10.2020