Коли я можу використовувати динамічне програмування, щоб зменшити часову складність мого рекурсивного алгоритму?


13

Динамічне програмування може скоротити час, необхідний для виконання рекурсивного алгоритму. Я знаю, що динамічне програмування може допомогти зменшити складність часу алгоритмів. Чи загальні умови такі, що при задоволенні рекурсивного алгоритму буде означати, що використання динамічного програмування зменшить складність часу алгоритму? Коли я повинен використовувати динамічне програмування?


Питання, пов’язані з цим: Вирішення
Рафаель

Відповіді:


9

Динамічне програмування корисно, якщо ваш рекурсивний алгоритм багато разів доходить до одних і тих же ситуацій (вхідних параметрів). Існує загальна трансформація з рекурсивних алгоритмів в динамічне програмування, відоме як пам'ятка , в якій є таблиця, в якій зберігаються всі результати, коли-небудь обчислені вашою рекурсивною процедурою. Коли рекурсивна процедура викликається на наборі входів, які вже були використані, результати просто вибираються з таблиці. Це зводить рекурсивні Фібоначчі до ітеративних Фібоначчі.

Динамічне програмування може бути ще розумнішим, застосовуючи більш конкретні оптимізації. Наприклад, іноді немає необхідності зберігати всю таблицю в пам'яті в будь-який момент часу.


Тоді лічильником буде те, що в будь-який час складність простору запам'ятовування більша, ніж вхідні дані (можливо, просто> O (N)), швидше за все, динамічне програмування не допоможе. Тобто, коли ти нечасто стикаєшся з тією ж ситуацією.
edA-qa mort-ora-y

1
Пам'ятка! = Динамічне програмування!
Рафаель

1
Я не думаю, що ми це говоримо, але питання вказує на зниження часової складності. Динамічне програмування самостійно просто розділяє проблему. Динамічне програмування + запам'ятовування - це загальний спосіб поліпшити часову складність, де це можливо .
edA-qa mort-ora-y

@ edA-qamort-ora-y: Правильно. Я думаю, що важливо чітко це зазначити, оскільки, очевидно, ОП плутає / змішує поняття.
Рафаель

8

Якщо ви просто прагнете прискорити рекурсивний алгоритм, запам'ятовування може бути достатньо. Це техніка зберігання результатів викликів функцій, щоб майбутні дзвінки з тими ж параметрами могли просто використати результат. Це застосовно, якщо (і лише якщо) ваша функція

  • не має побічних ефектів і
  • залежить лише від його параметрів (тобто не від певного стану).

Це заощадить ваш час, якщо (і тільки якщо) функція буде викликана з тими ж параметрами знову і знову. Популярні приклади включають рекурсивне визначення чисел Фібоначчі, тобто

f(0)=0f(1)=1f(н+2)=f(н+1)+f(н), н0

ff(н)f(н+1)

Зауважте, що, натомість, запам'ятовування є поряд із марними для таких алгоритмів, як сортування злиття: зазвичай декілька (якщо такі є) часткові списки однакові, а перевірки рівності - дорогі (сортування лише трохи дорожче!)

У практичних втіленнях спосіб зберігання результатів має велике значення для продуктивності. Використання хеш-таблиць може бути очевидним вибором, але може порушити місцевість. Якщо ваші параметри невід'ємні цілі числа, масиви є природним вибором, але можуть спричинити величезні накладні витрати на пам'ять, якщо ви використовуєте лише деякі записи. Тому запам'ятовування - це компроміс між ефектом і вартістю; чи окупається це, залежить від конкретного сценарію.


Динамічне програмування - це зовсім інший звір. Це застосовно до проблем із майном, яке

  • його можна розділити на підпрограми (можливо, більш ніж одним способом),
  • ці підпрограми можна вирішити самостійно,
  • (оптимальні) рішення цих підпроблем можуть поєднуватися з (оптимальними) рішеннями вихідної задачі та
  • підпроблеми мають однакову властивість (або тривіальні).

Це зазвичай (неявно) мається на увазі, коли люди посилаються на Принцип оптимальності Беллмана .

Тепер це лише описує клас проблем, які можуть бути виражені певним видом рекурсії. Оцінка цих питань (часто) ефективна, оскільки запам'ятовування може бути застосоване з великим ефектом (див. Вище); Зазвичай менші підпрограми виникають як частина багатьох більших проблем. Популярні приклади включають відстань редагування та алгоритм Беллмана-Форда .


Ви кажете, що є випадки, коли динамічне програмування призведе до кращої складності в часі, але запам'ятовування не допоможе (або принаймні не так сильно)? Чи є у вас приклади? Або ви просто говорите, що динамічне програмування корисне лише для набору проблем, де є запам'ятовування?
svick

@svick: Динамічне программування не прискорить нічого по суті, тільки якщо рекурсія DP оцінюється з мемоізація (який, як правило , () випадок!). Знову ж таки: DP - це спосіб моделювання проблем з точки зору рекурсії, мемуалізація - це техніка прискорення відповідних рекурсивних алгоритмів (незалежно від того, DP). Немає сенсу порівнювати обидва безпосередньо. Звичайно, ви намагаєтеся моделювати проблему як DP, тому що ви розраховуєте застосувати мемуалізацію і, отже, вирішити її швидше, ніж могли би наївні (r) підходи. Але точка зору DP не завжди призводить до найбільш ефективного алгоритму.
Рафаель

Якщо у вас є декілька доступних процесорів, динамічне програмування значно покращує продуктивність у реальному світі, оскільки ви можете паралелізувати їх частини. Однак насправді це не змінює складності часу.
edA-qa mort-ora-y

@ edA-qamort-ora-y: Це справедливо для будь-якої рекурсії. Однак не ясно, що це створює хорошу швидкість, оскільки запам'ятовування є менш ефективним за межами процесора.
Рафаель

Корекція: оцінка DP-рецидивів наївно все ще може бути (набагато) швидше, ніж груба сила; пор. тут .
Рафаель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.