Динамическое программирование дает вам возможность подумать о разработке алгоритма. Это часто очень полезно.
Методы памяти и восходящие методы дают вам правило / метод для преобразования рекуррентных отношений в код. Мемуализация - относительно простая идея, но лучшие идеи часто бывают!
Динамическое программирование дает вам структурированный способ думать о времени выполнения вашего алгоритма. Время выполнения в основном определяется двумя числами: количеством подзадач, которые вы должны решить, и временем, которое требуется для решения каждой подзадачи. Это обеспечивает удобный и простой способ думать о проблеме разработки алгоритма. Когда у вас есть рекуррентное отношение кандидата, вы можете посмотреть на него и очень быстро понять, каким может быть время выполнения (например, вы часто можете очень быстро определить, сколько будет подзадач, что является нижней границей для время выполнения: если вы решаете экспоненциально много подзадач, то повторение, вероятно, не будет хорошим подходом). Это также поможет вам исключить возможные декомпозиции подзадач. Например, если у нас есть строкаS [ 1 .. i ] S [ j . , n ] S [ i . , j ] n S nS[ 1 .. n ]определение подзадачи с помощью префикса или суффикса или подстроки может быть разумным (количество подзадач является полиномиальным по ), но определение подзадачи по подпоследовательности вряд ли будет хорошим подходом (число подзадач экспоненциально по ). Это позволяет вам обрезать «пространство поиска» возможных повторений.S[ 1 .. я ]S[j..n]S[i..j]nSn
Динамическое программирование дает вам структурированный подход для поиска возможных рекуррентных отношений. Эмпирически этот подход часто эффективен. В частности, есть некоторые эвристические / общие шаблоны, которые вы можете распознать для общих способов определения подзадач в зависимости от типа ввода. Например:
Если входные данные являются положительным целым числом , один из возможных способов определения подзадачи состоит в замене меньшим целым числом (st ).п п ' 0 ≤ N ' ≤ пnnn′0≤n′≤n
Если входные данные представляют собой строку , некоторые возможные способы определения подзадачи включают: заменить префиксом ; заменить суффиксом ; замените подстрокой . (Здесь подзадача определяется выбором .)S [ 1 .. n ] S [ 1 .. i ] S [ 1 .. n ] S [ j . , n ] S [ 1 .. n ] S [ i . , j ] i , jS[1..n]S[1..n]S[1..i]S[1..n]S[j..n]S[1..n]S[i..j]i,j
Если вход представляет собой список , сделайте то же самое, что и для строки.
Если входные данные представляют собой дерево , один из возможных способов определения подзадачи состоит в том, чтобы заменить любым поддеревом (т. Е. Выбрать узел и заменить поддеревом, корнем которого является ; подзадача определяется выбором ).Т Т х Т х хTTTxTxx
Если вход представляет собой пару , то рекурсивно посмотрите на тип и тип чтобы определить способ выбора подзадачи для каждого. Другими словами, одним из возможных способов определения подзадачи является замена на где - это подзадача для а - это подзадача для . (Вы также можете рассмотреть подзадачи вида или .)x y ( x , y ) ( x ′ , y ′ ) x ′ x y ′ y ( x , y ′ ) ( x ′ , y )(x,y)xy(x,y)(x′,y′)x′xy′y(x,y′)(x′,y)
И так далее. Это дает вам очень полезную эвристику: просто взглянув на сигнатуру метода, вы можете найти список возможных способов определения подзадач. Другими словами, просто взглянув на постановку задачи - рассматривая только типы входных данных - вы можете найти несколько возможных способов определения подзадачи.
Это часто очень полезно. Он не говорит вам, что такое рекуррентное отношение, но когда у вас есть конкретный выбор, как определить подзадачу, часто не так уж сложно разработать соответствующее рекуррентное отношение. Таким образом, он часто превращает разработку алгоритма динамического программирования в структурированный опыт. На бумаге вы записываете список возможных способов определения подзадач (используя эвристику выше). Затем для каждого кандидата вы пытаетесь записать рекуррентное отношение и оцените его время выполнения путем подсчета количества подзадач и времени, затраченного на каждую подзадачу. Испытав каждого кандидата, вы оставляете лучшего, которого смогли найти. Предоставление некоторой структуры процессу разработки алгоритма является основной помощью, так как в противном случае разработка алгоритма может быть пугающей (