Quando posso usare la programmazione dinamica per ridurre la complessità temporale del mio algoritmo ricorsivo?


13

La programmazione dinamica può ridurre il tempo necessario per eseguire un algoritmo ricorsivo. So che la programmazione dinamica può aiutare a ridurre la complessità temporale degli algoritmi. Le condizioni generali sono tali che se soddisfatte da un algoritmo ricorsivo implicherebbe che l'uso della programmazione dinamica ridurrà la complessità temporale dell'algoritmo? Quando dovrei usare la programmazione dinamica?


Risposte:


9

La programmazione dinamica è utile se l'algoritmo ricorsivo si trova più volte nelle stesse situazioni (parametri di input). Esiste una trasformazione generale da algoritmi ricorsivi a programmazione dinamica nota come memoization , in cui è presente una tabella in cui sono memorizzati tutti i risultati calcolati dalla procedura ricorsiva. Quando viene richiamata la procedura ricorsiva su una serie di input già utilizzati, i risultati vengono semplicemente recuperati dalla tabella. Ciò riduce Fibonacci ricorsivo a Fibonacci iterativo.

La programmazione dinamica può essere ancora più intelligente, applicando ottimizzazioni più specifiche. Ad esempio, a volte non è necessario memorizzare l'intera tabella in memoria in un dato momento.


Il contatore sarebbe quindi che ogni volta che la complessità dello spazio della memoizzazione è maggiore dei dati di input (forse solo> O (N)), è probabile che la programmazione dinamica non sia di aiuto. Cioè, quando incontri raramente la stessa situazione.
edA-qa mort-ora-y

1
Memoisation! = Programmazione dinamica!
Raffaello

1
Non credo che lo stiamo dicendo, ma la domanda indica la riduzione della complessità temporale. La programmazione dinamica da sola separa semplicemente il problema. La programmazione dinamica + memoization è un modo generico per migliorare la complessità temporale ove possibile .
edA-qa mort-ora-y

@ edA-qamort-ora-y: giusto. Penso che sia importante precisarlo chiaramente, poiché apparentemente l'OP confonde / mescola i concetti.
Raffaello

8

Se cerchi solo di accelerare il tuo algoritmo ricorsivo, la memoria potrebbe essere sufficiente. Questa è la tecnica di memorizzazione dei risultati delle chiamate di funzione in modo che le chiamate future con gli stessi parametri possano semplicemente riutilizzare il risultato. Questo è applicabile se (e solo se) la tua funzione

  • non ha effetti collaterali e
  • dipende solo dai suoi parametri (cioè non da alcuni stati).

Ti farà risparmiare tempo se (e solo se) la funzione viene chiamata ripetutamente con gli stessi parametri. Esempi popolari includono la definizione ricorsiva dei numeri di Fibonacci, cioè

f(0)=0f(1)=1f(n+2)=f(n+1)+f(n), n0

ff(n)f(n+1)

Si noti che, al contrario, la memoria è quasi inutile per algoritmi come unisci ordinamento: di solito pochi (se presenti) elenchi parziali sono identici e i controlli di uguaglianza sono costosi (l'ordinamento è solo leggermente più costoso!).

Nelle implementazioni pratiche, il modo in cui archiviate i risultati è di grande importanza per le prestazioni. L'uso delle tabelle hash può essere la scelta ovvia, ma potrebbe interrompere la località. Se i parametri sono numeri interi non negativi, le matrici sono una scelta naturale ma possono causare un sovraccarico di memoria enorme se si utilizzano solo alcune voci. Pertanto, la memoria è un compromesso tra effetto e costo; se ripaga dipende dal tuo scenario specifico.


La programmazione dinamica è completamente un'altra bestia. È applicabile a problemi con la proprietà che

  • può essere suddiviso in sottoproblemi (probabilmente in più di un modo),
  • questi sottoproblemi possono essere risolti in modo indipendente,
  • Le soluzioni (ottimali) di tali sottoproblemi possono essere combinate con soluzioni (ottimali) del problema originale e
  • i sottoproblemi hanno la stessa proprietà (o sono banali).

Questo è generalmente (implicitamente) implicito quando le persone invocano il Principio di ottimalità di Bellman .

Ora, questo descrive solo una classe di problemi che possono essere espressi da un certo tipo di ricorsione. La valutazione di questi è (spesso) efficace perché la memoisation può essere applicata con grande efficacia (vedi sopra); di solito, sottoproblemi minori si verificano come parti di molti problemi più grandi. Esempi popolari includono la modifica della distanza e l' algoritmo Bellman-Ford .


Stai dicendo che ci sono casi in cui la programmazione dinamica porterà a una migliore complessità temporale, ma la memoizzazione non sarebbe di aiuto (o almeno non tanto)? Hai qualche esempio? O stai solo dicendo che la programmazione dinamica è utile solo per un sottoinsieme di problemi in cui è la memoizzazione?
svick,

@svick: la programmazione dinamica non accelera nulla di per sé, solo se la ricorsione DP viene valutata con memoisation (che di solito (!) è il caso). Ancora: la DP è un modo per modellare i problemi in termini di ricorsione, la memoisation è una tecnica per accelerare algoritmi ricorsivi adeguati (non importa se DP). Non ha senso confrontare entrambi direttamente. Ovviamente provi a modellare un problema come DP perché ti aspetti di applicare la memoisation e quindi di risolverlo più rapidamente di quanto potrebbero fare gli approcci ingenui. Ma un punto di vista DP non porta sempre all'algoritmo più efficiente.
Raffaello

Se disponi di più processori, la programmazione dinamica migliora notevolmente le prestazioni del mondo reale in quanto puoi parallelizzare le parti. Tuttavia, in realtà non cambia la complessità del tempo.
edA-qa mort-ora-y

@ edA-qamort-ora-y: questo è vero per qualsiasi ricorsione. Tuttavia, non è chiaro che ciò crei una buona accelerazione, poiché la memoria è meno efficiente oltre i confini del processore.
Raffaello

Correzione: la valutazione delle ricadute DP in modo ingenuo può ancora essere (molto) più veloce della forza bruta; cf. QUI .
Raffaello
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.