Differenza tra Divide e Conquer Algo e Dynamic Programming


140

Qual è la differenza tra Divide e Conquer Algorithms e Dynamic Programming Algorithms? In che modo i due termini sono diversi? Non capisco la differenza tra loro.

Per favore, fai un semplice esempio per spiegare qualsiasi differenza tra i due e su quale terreno sembrano essere simili.

Risposte:


156

Dividere e conquistare

Divide and Conquer funziona dividendo il problema in sotto-problemi, conquistando ricorsivamente ogni sotto-problema e combinando queste soluzioni.

Programmazione dinamica

La programmazione dinamica è una tecnica per risolvere problemi con sottoproblemi sovrapposti. Ogni sotto-problema viene risolto una sola volta e il risultato di ciascun sotto-problema viene archiviato in una tabella (generalmente implementata come una matrice o una tabella hash) per riferimenti futuri. Queste soluzioni secondarie possono essere utilizzate per ottenere la soluzione originale e la tecnica di memorizzazione delle soluzioni del problema secondario è nota come memoization.

Potresti pensare DP = recursion + re-use

Un classico esempio per capire la differenza sarebbe vedere entrambi questi approcci per ottenere l'ennesimo numero di fibonacci. Controllare questo materiale dal MIT.


Approccio Divide and Conquer Approccio Divide and Conquer

Approccio di programmazione dinamica inserisci qui la descrizione dell'immagine


9
come hai fatto le immagini? usando il mouse?
Vihaan Verma,

34
Penso che la linea più importante in tutta questa risposta sia: "sottoproblemi sovrapposti". DP ce l'ha, Divide and Conquer no
Hasan Iqbal,

@HasanIqbalAnik Il problema secondario sovrapposto indica un problema che si verifica più volte. Come risolvere fn-2 nell'esempio mostrato sopra. Quindi in D&C c'è e per questo non è efficiente come DP.
Meena Chaudhary,

1
Strano! "Sottoproblemi sovrapposti" stai parlando del problema, ma la "programmazione dinamica" è una specie di algoritmo. Penso che sia importante distinguere "problemi" e "algoritmi".
ZHU,

Sì, DP memorizza le porzioni sovrapposte per ottenere un vantaggio su Divide and Conquer.
imagerhat quel

25

L'altra differenza tra divide e conquistare e la programmazione dinamica potrebbe essere:

Dividere e conquistare:

  1. Lavora di più sui sotto-problemi e quindi ha un consumo di tempo maggiore.
  2. Nel dividere e conquistare i sotto-problemi sono indipendenti l'uno dall'altro.

Programmazione dinamica:

  1. Risolve i problemi secondari una sola volta e quindi li memorizza nella tabella.
  2. Nella programmazione dinamica il sotto-problema non è indipendente.

Gli algoritmi di divisione e conquista non svolgono necessariamente più lavoro delle loro alternative DP. Un esempio è l'algoritmo di Erickson per la ricerca delle progressioni aritmetiche massime.
Michael Foukarakis,

17

a volte durante la programmazione ricorsiva, si chiama la funzione con gli stessi parametri più volte, il che è inutile.

I famosi numeri di Fibonacci di esempio:

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

Eseguiamo 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

Quindi abbiamo chiamato: 1 volte F (4) 2 volte F (3) 3 volte F (2) 2 volte F (1)

Approccio di programmazione dinamica: se si chiama una funzione con lo stesso parametro più di una volta, salvare il risultato in una variabile per accedervi direttamente alla volta successiva. Il modo iterativo:

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

Chiamiamo di nuovo F (5):

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

Come puoi vedere, ogni volta che hai bisogno della chiamata multipla accedi alla variabile corrispondente per ottenere il valore invece di ricalcolarlo.

A proposito, la programmazione dinamica non significa convertire un codice ricorsivo in un codice iterativo. Puoi anche salvare i subresults in una variabile se vuoi un codice ricorsivo. In questo caso la tecnica si chiama memoization. Per il nostro esempio è simile al seguente:

// 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]                
    }
}

Quindi la relazione con Divide and Conquer è che gli algoritmi D&D si basano sulla ricorsione. E alcune versioni hanno questa "chiamata a più funzioni con lo stesso problema con i parametri". Cerca "moltiplicazione a catena di matrici" e "sottosequenza comune più lunga" per tali esempi in cui DP è necessario per migliorare la T (n) dell'algoritmo D&D.


17

Somiglianze di programmazione dinamica e divisione e conquista

Per come la vedo per ora posso dire che la programmazione dinamica è un'estensione del paradigma di divisione e conquista .

Non li tratterei come qualcosa di completamente diverso. Perché entrambi funzionano abbattendo ricorsivamente un problema in due o più sotto-problemi dello stesso tipo o correlati, fino a quando questi non diventano abbastanza semplici da essere risolti direttamente. Le soluzioni ai problemi secondari vengono quindi combinate per fornire una soluzione al problema originale.

Quindi perché abbiamo ancora nomi di paradigmi diversi allora e perché ho chiamato la programmazione dinamica un'estensione. È perché l'approccio di programmazione dinamica può essere applicato al problema solo se il problema ha determinate restrizioni o prerequisiti . E dopo che la programmazione dinamica estende l'approccio alla divisione e alla conquista con la memoizzazione o la tabulazione tecnica della .

Andiamo passo dopo passo ...

Prerequisiti / restrizioni di programmazione dinamica

Come abbiamo appena scoperto, ci sono due attributi chiave che il problema di divisione e conquista deve avere affinché la programmazione dinamica sia applicabile:

  • Sottostruttura  ottimale - la soluzione ottimale può essere costruita da soluzioni ottimali dei suoi sottoproblemi

  • Sotto-problemi sovrapposti  : il problema può essere suddiviso in sottoproblemi che vengono riutilizzati più volte o un algoritmo ricorsivo per il problema risolve ripetutamente lo stesso sottoproblema anziché generare sempre nuovi sottoproblemi

Una volta soddisfatte queste due condizioni, possiamo dire che questo problema di divisione e conquista può essere risolto utilizzando un approccio di programmazione dinamica.

Estensione di programmazione dinamica per Divide and Conquer

L'approccio di programmazione dinamica estende l'approccio alla divisione e alla conquista con due tecniche ( memoizzazione e tabulazione ) che hanno entrambe lo scopo di archiviare e riutilizzare soluzioni con problemi secondari che possono migliorare drasticamente le prestazioni. Ad esempio, l'implementazione ricorsiva ingenua della funzione di Fibonacci ha una complessità temporale in O(2^n)cui la soluzione DP fa lo stesso con solo O(n)tempo.

La memorizzazione (riempimento cache top-down) si riferisce alla tecnica di memorizzazione nella cache e riutilizzo dei risultati precedentemente calcolati. La fibfunzione memorizzata sarebbe quindi simile a questa:

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

La tabulazione (riempimento della cache dal basso verso l'alto) è simile ma si concentra sul riempimento delle voci della cache. Il calcolo dei valori nella cache viene eseguito più facilmente in modo iterativo. La versione di tabulazione fibsarebbe simile a questa:

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

Puoi leggere di più sulla comparazione della memoizzazione e della tabulazione qui .

L'idea principale che dovresti capire qui è che, poiché il nostro problema di divisione e conquista ha sovrapposizioni di sotto-problemi, diventa possibile la memorizzazione nella cache delle soluzioni di sotto-problemi e quindi la memoizzazione / tabulazione salgono sulla scena.

Quindi qual è la differenza tra DP e DC dopo tutto

Dato che ora conosciamo i prerequisiti DP e le sue metodologie, siamo pronti a mettere tutto ciò che è stato menzionato sopra in una sola immagine.

Programmazione dinamica vs Divide-and-Conquer

Se vuoi vedere esempi di codice puoi dare un'occhiata a una spiegazione più dettagliata qui dove troverai due esempi di algoritmo: Ricerca binaria e Distanza minima di modifica (Levenshtein Distance) che illustrano la differenza tra DP e DC.


1
Offtopic: hai usato una tavoletta grafica per disegnarla?
Geon George,

1
@GeonGeorge no, il disegno è stato realizzato a penna e poi scansionato
Oleksii Trekhleb

questa è una delle migliori risposte che ho letto sull'organizzazione di DP
Ridhwaan Shakeel il

8

Presumo che tu abbia già letto Wikipedia e altre risorse accademiche su questo, quindi non riciclerò nessuna di queste informazioni. Devo anche avvertire che non sono affatto un esperto di informatica, ma condividerò i miei due centesimi sulla mia comprensione di questi argomenti ...

Programmazione dinamica

Suddivide il problema in sottoproblemi discreti. L'algoritmo ricorsivo per la sequenza di Fibonacci è un esempio di Programmazione dinamica, perché risolve per fib (n) risolvendo prima per fib (n-1). Per risolvere il problema originale, risolve un altro problema .

Dividere e conquistare

Questi algoritmi in genere risolvono simili problemi del problema, quindi li mettono insieme alla fine. Mergesort è un classico esempio di divisione e conquista. La differenza principale tra questo esempio e l'esempio di Fibonacci è che in una fusione, la divisione può (teoricamente) essere arbitraria e, indipendentemente da come la dividi, stai ancora fondendo e ordinando. La stessa quantità di lavoro deve essere fatta per unire l'array, indipendentemente da come lo divida. Risolvere per fib (52) richiede più passaggi che risolvere per fib (2).


5

Penso Divide & Conquera un approccio ricorsivo eDynamic Programming al riempimento della tabella.

Ad esempio, Merge Sortè un Divide & Conqueralgoritmo, come in ogni passaggio, dividi l'array in due metà, invidi ricorsivamente Merge Sortle due metà e quindi le unisci.

Knapsackè un Dynamic Programmingalgoritmo mentre riempi una tabella che rappresenta soluzioni ottimali ai sottoproblemi dello zaino complessivo. Ogni voce nella tabella corrisponde al valore massimo che puoi portare in un sacco di peso con gli articoli 1-j.


1
Sebbene ciò sia vero per molti casi, non è sempre vero che archiviamo i risultati dei sottoproblemi in una tabella.
Gokul

2

Divide and Conquer prevede tre passaggi per ogni livello di ricorsione:

  1. Dividi il problema in sottoproblemi.
  2. Conquista i sottoproblemi risolvendoli in modo ricorsivo.
  3. Combina la soluzione per i sottoproblemi nella soluzione per il problema originale.
    • È un approccio dall'alto verso il basso .
    • Fa più lavoro sui sottoproblemi e quindi ha un consumo di tempo maggiore.
    • per esempio. L'ennesimo termine della serie di Fibonacci può essere calcolato in O (2 ^ n) complessità temporale.

La programmazione dinamica prevede i seguenti quattro passaggi:

1. Caratterizzare la struttura delle soluzioni ottimali.
2. Definire in modo ricorsivo i valori di soluzioni ottimali.
3. Calcola il valore di soluzioni ottimali.
4. Costruire una soluzione ottimale dalle informazioni calcolate .

  • È un Bottom-up approccio dal .
  • Consumo di tempo inferiore rispetto alla divisione e alla conquista, poiché utilizziamo i valori calcolati in precedenza, anziché eseguire nuovamente il calcolo.
  • per esempio. L'ennesimo termine della serie di Fibonacci può essere calcolato nella complessità temporale O (n).

Per una comprensione più semplice, vediamo dividere e conquistare come una soluzione di forza bruta e la sua ottimizzazione come programmazione dinamica.

NB gli algoritmi di divisione e conquista con sottoproblemi sovrapposti possono essere ottimizzati solo con dp.


Divide and Conquer è bottom-up e la programmazione dinamica è top-down
Bahgat Mashaly

0
  • Dividere e conquistare
    • Si sono rotti in sotto-problemi non sovrapposti
    • Esempio: numeri fattoriali ovvero fact (n) = n * fact (n-1)
fact(5) = 5* fact(4) = 5 * (4 * fact(3))= 5 * 4 * (3 *fact(2))= 5 * 4 * 3 * 2 * (fact(1))

Come possiamo vedere sopra, nessun fatto (x) viene ripetuto, quindi fattoriale ha problemi non sovrapposti.

  • Programmazione dinamica
    • Si sono rotti in sotto-problemi sovrapposti
    • Esempio: numeri di Fibonacci ovvero fib (n) = fib (n-1) + fib (n-2)
fib(5) = fib(4) + fib(3) = (fib(3)+fib(2)) + (fib(2)+fib(1))

Come possiamo vedere sopra, fib (4) e fib (3) usano entrambi fib (2). allo stesso modo così tanti fib (x) vengono ripetuti. ecco perché Fibonacci ha sotto-problemi sovrapposti.

  • Come risultato della ripetizione del sotto-problema in DP, possiamo conservare tali risultati in una tabella e risparmiare sforzo di calcolo. questo si chiama memoization
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.