Memoizzazione senza array


14

Nell'Introduzione agli algoritmi di Cormen et al. , La sezione 15.3 Elementi di programmazione dinamica spiega la memoizzazione come segue:

Un algoritmo ricorsivo memorizzato mantiene una voce in una tabella per la soluzione di ciascun sottoproblema. Ogni voce della tabella contiene inizialmente un valore speciale per indicare che la voce deve ancora essere compilata. Quando il sottoproblema viene rilevato per la prima volta mentre si sviluppa l'algoritmo ricorsivo, la sua soluzione viene calcolata e quindi memorizzata nella tabella. Ogni volta che incontriamo questo sottoproblema, cerchiamo semplicemente il valore memorizzato nella tabella e lo restituiamo.

E aggiunge, come nota a piè di pagina:

Questo approccio presuppone che conosciamo l'insieme di tutti i possibili parametri dei sottoproblemi e che abbiamo stabilito la relazione tra posizioni della tabella e sottoproblemi. Un altro approccio, più generale, è quello di memoize usando l'hash con i parametri del sottoproblema come chiavi.

Esistono problemi DP noti che richiedono (o semplificano) la memorizzazione di valori memorizzati in un dizionario anziché in un array (multidimensionale)?


Sfondo: se questo è di qualche utilità, la ragione di questa domanda è che sto cercando di motivare l'idea di alberi di ricerca binari (auto-bilanciati) a persone che hanno appena visto la programmazione dinamica.


Nel software reale con cui lavoro, il memoizing può sfruttare il fatto che una funzione relativamente costosa (come exp , log o pow ) può essere chiamata da molti punti diversi del codice e viene spesso chiamata più volte in ordine con il stesso valore da ogni posizione di codice particolare. In tal caso, il "dizionario" può essere un singolo valore memorizzato in una variabile specifica della posizione del codice.
Mike Dunlavey,

Risposte:


5

Probabilmente ci sono esempi migliori, ma eccone uno, fuori dalla mia testa:

S,Td>d


3

Vorrei fornire 2 esempi.

0-1 Problema allo zaino

Nel caso del problema dello zaino 0-1 (dove W è una capacità dello zaino e N è una quantità di oggetti), a volte è meglio usare la programmazione dinamica top-down con memoization, invece dell'enumerazione sistematica bottom-up dell'intero array 2D di dimensioni WxN (specialmente nel caso in cui la capacità dello zaino W sia grande, ma la cardinalità dell'insieme delle combinazioni consentite di pesi degli oggetti è molto più piccola di W ).

In questo caso, per motivi di economia di una memoria, si può scegliere di utilizzare il dizionario per la memoizzazione anziché l'array 2D.

Algoritmo di analisi Earley

L'algoritmo di analisi Earley può essere utilizzato per l'analisi di istruzioni, che appartengono a una grammatica senza contesto. A differenza dell'algoritmo CYK (che si basa sull'approccio DP bottom-up e utilizza una tabella 2D per la memoizzazione) - Il parser Earley utilizza l'approccio top-down in combinazione con il grafico di analisi per la memoization.

Il grafico di analisi contiene le produzioni grammaticali parzialmente analizzate (ad es., Data la produzione X → AB , e dopo un corretto abbinamento della parte A di questa produzione, memorizziamo la produzione parzialmente abbinata all'interno del grafico di analisi: X → A • B , dove punti sono alla parte già abbinata).

La quantità di colonne all'interno del grafico di analisi è uguale alla quantità di token. Tuttavia, in generale, potrebbe essere molto complicato stimare la quantità di produzioni grammaticali parzialmente analizzate per colonna (dipende dalla grammatica e dalla particolare sequenza di token).

Pertanto, è più conveniente implementare il grafico di analisi basato sulla struttura dei dati del dizionario.

Nel dominio dell'elaborazione del linguaggio naturale, di solito il pareser di Earley è la scelta più conveniente, perché non richiede la forma normale di Chomsky per la grammatica (e CYK ha tale requisito).


0

Nella mia esperienza di programmazione competitiva, l'uso di una tabella hash (Python dicto simile) è spesso più conveniente rispetto all'utilizzo di un array, poiché qualsiasi tipo di dati hash può essere usato come chiave, come stringhe, set ( frozensetin Python) o tuple come (string, int)ecc. Se si utilizza un array, è necessario tradurre manualmente tutte le chiavi in ​​numeri interi (a partire da 0), il che richiede ulteriore lavoro e, come le note di origine, potrebbe non essere possibile se non si conosce in anticipo lo spazio delle chiavi. Quindi i dizionari sono piuttosto più generali delle matrici.

Naturalmente, se riesci a cavartela usando le matrici, è probabilmente più veloce perché evita ripetutamente il calcolo degli hash (d'altra parte richiede prima l'inizializzazione dell'intero array, che richiede tempo e memoria), ma potrebbe richiedere più tempo per scrivere il codice perché devi fare il lavoro extra di tradurre tutte le chiavi in ​​numeri interi.

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.