Різниця між розділенням і підкоренням Algo та динамічним програмуванням


140

Чим відрізняються алгоритми ділення та перемоги від алгоритмів динамічного програмування? Чим два терміни відрізняються? Я не розумію різниці між ними.

Візьміть простий приклад, щоб пояснити будь-яку різницю між ними та за якою ознакою вони схожі.

Відповіді:


156

Розділяй і володарюй

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

Динамічне програмування

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

Ви можете подумати DP = recursion + re-use

Класичним прикладом, щоб зрозуміти різницю, було б бачити обидва ці підходи до отримання номера n-го поля. Перевірте цей матеріал від MIT.


Підхід розділити і перемогти Підхід розділити і перемогти

Підхід до динамічного програмування введіть тут опис зображення


9
як ти робив образи? за допомогою миші?
Vihaan Verma

34
Я думаю, що найважливіший рядок у всій цій відповіді полягає в тому, що: "підпрограми, що перекриваються". DP має, Діліться і перемагайте
Хасан Ікбал

@HasanIqbalAnik Проблема, що перекривається, означає проблему, яка виникає знову і знову. Як і рішення fn-2 у наведеному вище прикладі. Тож у науково-дослідних і дослідницьких роботах вона є, і саме тому вона не настільки ефективна, як DP.
Meena Chaudhary

1
Дивно! "Перекриття підпроблем" ви говорите про проблему, але "динамічне програмування" - це свого роду алгоритм. Я думаю, що важливо розрізняти «проблеми» та «алгоритми».
ЖУ

Так, DP запам'ятовує частини, що перекриваються, щоб отримати перевагу перед діленням і перемогою.
уявіть, що

25

Іншою відмінністю між програмою поділу, перемоги та динамічного програмування може бути:

Розділяй і володарюй:

  1. Більше працює над субпроблемами, а значить, витрачається більше часу.
  2. При поділі та підкоренні субпроблеми не залежать одна від одної.

Динамічне програмування:

  1. Вирішує підзадачі лише один раз, а потім зберігає їх у таблиці.
  2. У динамічному програмуванні підпроблема не є незалежною.

Алгоритми розділення та перемоги не обов'язково виконують більше роботи, ніж їх альтернативи DP. Одним із прикладів є алгоритм Еріксона для пошуку максимальних арифметичних прогресій.
Майкл Фукаракіс

17

іноді, програмуючи рекурсивно, ви викликаєте функцію з одними і тими ж параметрами кілька разів, що є нецікавим.

Відомий приклад чисел Фібоначчі:

           index: 1,2,3,4,5,6...
Fibonacci number: 1,1,2,3,5,8...

function F(n) {
    if (n < 3)
        return 1
    else
        return F(n-1) + F(n-2)
}

Запустимо F (5):

F(5) = F(4) + F(3)
     = {F(3)+F(2)} + {F(2)+F(1)}
     = {[F(2)+F(1)]+1} + {1+1}
     = 1+1+1+1+1

Отже, ми назвали: 1 раз F (4) 2 рази F (3) 3 рази F (2) 2 рази F (1)

Підхід до динамічного програмування: якщо ви викликаєте функцію з одним і тим же параметром не один раз, збережіть результат у змінній, щоб безпосередньо отримати доступ до нього в наступний раз. Ітераційний спосіб:

if (n==1 || n==2)
    return 1
else
    f1=1, f2=1
    for i=3 to n
         f = f1 + f2
         f1 = f2
         f2 = f

Давайте подзвонимо ще раз F (5):

fibo1 = 1
fibo2 = 1 
fibo3 = (fibo1 + fibo2) = 1 + 1 = 2
fibo4 = (fibo2 + fibo3) = 1 + 2 = 3
fibo5 = (fibo3 + fibo4) = 2 + 3 = 5

Як бачите, щоразу, коли вам потрібен багаторазовий дзвінок, ви просто отримуєте доступ до відповідної змінної, щоб отримати значення замість перерахунку.

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

// declare and initialize a dictionary
var dict = new Dictionary<int,int>();
for i=1 to n
    dict[i] = -1

function F(n) {
    if (n < 3)
        return 1
    else
    {
        if (dict[n] == -1)
            dict[n] = F(n-1) + F(n-2)

        return dict[n]                
    }
}

Отже, відносини до розділення та перемоги полягають у тому, що алгоритми дослідження та розробки залежать від рекурсії. І деякі версії з них мають цей "виклик декількох функцій з однаковою проблемою". Шукайте "множення матричного ланцюга" та "найдовшу спільну послідовність" для таких прикладів, коли DP необхідний для поліпшення T (n) алго D&D.


17

Динамічне програмування та подібність ділити-перемагати

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

Я б не ставився до них як до чогось зовсім іншого. Оскільки вони обидва працюють, рекурсивно розбиваючи проблему на дві або більше підпроблеми одного і того ж або спорідненого типу, поки вони не стануть досить простими, щоб їх вирішити безпосередньо. Розв’язання підзадач потім комбінуються, щоб дати вирішення вихідної проблеми.

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

Ходімо крок за кроком ...

Передумови / обмеження динамічного програмування

Як ми нещодавно з’ясували, є два ключових атрибути, які повинні мати поділ і перемогти, щоб динамічне програмування було застосовно:

  • Оптимальна підструктура  - оптимальне рішення може бути побудоване з оптимальних рішень його підпроблем

  • Перекриття субпроблем  - проблема може бути розбита на підпрограми, які повторно використовуються кілька разів, або рекурсивний алгоритм для проблеми вирішує ту саму підпроблему знову і знову, а не завжди генерує нові підпрограми.

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

Розширення динамічного програмування для розділення та перемоги

Підхід до динамічного програмування розширює підхід розділення та перемоги за допомогою двох прийомів ( запам'ятовування та табуляції ), які мають обох цілей для зберігання та повторного використання підпроблемних рішень, що може значно підвищити продуктивність. Наприклад, наївна рекурсивна реалізація функції Фібоначчі має складність у часі, O(2^n)коли рішення DP роблять те ж саме з O(n)часом.

Пам'ять (заповнення кешу зверху вниз) відноситься до техніки кешування та повторного використання раніше обчислених результатів. Запам'ятована fibфункція виглядатиме так:

memFib(n) {
    if (mem[n] is undefined)
        if (n < 2) result = n
        else result = memFib(n-2) + memFib(n-1)

        mem[n] = result
    return mem[n]
}

Таблиця (заповнення кешу знизу вгору) подібна, але зосереджена на заповненні записів кешу. Обчислення значень у кеші найпростіше робити повторно. Версія для таблиць fibвиглядатиме так:

tabFib(n) {
    mem[0] = 0
    mem[1] = 1
    for i = 2...n
        mem[i] = mem[i-2] + mem[i-1]
    return mem[n]
}

Ви можете прочитати більше про запам'ятовування та порівняння таблиць тут .

Основна ідея, яку ви повинні зрозуміти, полягає в тому, що через те, що наша проблема розділення і перемоги має перекриття підпроблем, кешування підпроблемних рішень стає можливим, і таким чином запам'ятовування / табуляція виходить на сцену.

Тож яка різниця між DP та DC Зрештою

Оскільки ми зараз знайомі з передумовами DP та його методологіями, ми готові поставити все, що було сказано вище, в одну картину.

Динамічне програмування проти поділу і перемоги

Якщо ви хочете побачити приклади коду, ви можете ознайомитись з більш детальним поясненням тут, де ви знайдете два приклади алгоритму: Двійковий пошук та Мінімальна відстань редагування (відстань Левенштейна), які ілюструють різницю між DP та DC.


1
Offtopic: Ви використовували графічний планшет, щоб намалювати це?
Геон Джордж

1
@GeonGeorge ні, малюнок був зроблений ручкою, а потім відсканований
Олексій Трехлеб

це одна з найкращих відповідей, які я читав про організацію DP
Ridhwaan Shakeel

8

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

Динамічне програмування

Розбиває проблему на дискретні підпрограми. Рекурсивний алгоритм послідовності Фібоначчі є прикладом динамічного програмування, оскільки він вирішує для fib (n) спочатку рішення для fib (n-1). Для того, щоб вирішити оригінальну задачу, вона вирішує іншу задачу.

Розділяй і володарюй

Ці алгоритми зазвичай вирішують подібні частини проблеми, а потім складають їх у кінці. Mergesort - класичний приклад поділу та перемоги. Основна відмінність цього прикладу від прикладу Фібоначчі полягає в тому, що в об'єднанні, поділ може (теоретично) бути довільним, і як би ви їх не розрізали, ви все ще зливаєтесь і сортуєте. Таку ж роботу потрібно виконати для об'єднання масиву, незалежно від того, як ви розділите його. Розв’язування для fib (52) вимагає більше кроків, ніж рішення для fib (2).


5

Я розглядаю це Divide & Conquerяк рекурсивний підхід і Dynamic Programmingяк заповнення таблиць.

Наприклад, Merge Sortце Divide & Conquerалгоритм, так як на кожному кроці ви розділите масив на дві половини, рекурсивно зателефонуйте Merge Sortна дві половини і потім об'єднайте їх.

Knapsack- це Dynamic Programmingалгоритм, коли ви заповнюєте таблицю, що представляє оптимальні рішення підпроблем загального рюкзака. Кожен запис у таблиці відповідає максимальному значенню, яке ви можете нести в мішку з масою w із заданими предметами 1-j.


1
Хоча це справедливо для багатьох випадків, не завжди правда, що ми зберігаємо результати підпроблем у таблиці.
Gokul

2

Ділення та перемога включає три етапи на кожному рівні рекурсії:

  1. Розділіть задачу на підпрограми.
  2. Завоюйте підпроблеми, розв’язуючи їх рекурсивно.
  3. Об'єднайте рішення для підпроблем у рішення для вихідної проблеми.
    • Це підхід зверху вниз .
    • Це робить більше роботи над підпроблемами, а значить, витрачає більше часу.
    • напр. n-й член рядів Фібоначчі можна обчислити за часовою складністю O (2 ^ n).

Динамічне програмування передбачає наступні чотири кроки:

1. Охарактеризуйте структуру оптимальних рішень.
2. Рекурсивно визначити значення оптимальних рішень.
3. Обчисліть значення оптимальних рішень.
4. Побудуйте оптимальне рішення з обчисленої інформації .

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

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

NB алгоритми розділення та підкорення з підпрограмами, що перекриваються, можна оптимізувати лише за допомогою dp.


Розділити і перемогти - це знизу вгору, а динамічне програмування - зверху вниз
Бахгат Машали

0
  • Розділяй і володарюй
    • Вони зіткнулися з невідповідними підпроблемами
    • Приклад: фактичні числа, тобто факт (n) = n * факт (n-1)
fact(5) = 5* fact(4) = 5 * (4 * fact(3))= 5 * 4 * (3 *fact(2))= 5 * 4 * 3 * 2 * (fact(1))

Як ми можемо бачити вище, жоден факт (х) не повторюється, тому факторія не має проблем, що перетинаються.

  • Динамічне програмування
    • Вони зірвалися з перекриваючими підпроблемами
    • Приклад: числа Фібоначчі, тобто fib (n) = fib (n-1) + fib (n-2)
fib(5) = fib(4) + fib(3) = (fib(3)+fib(2)) + (fib(2)+fib(1))

Як ми бачимо вище, fib (4) і fib (3) обидва використовують fib (2). так само багато fib (x) повторюється. саме тому у Фібоначчі виникають супутні проблеми.

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