La programmazione dinamica ti offre un modo di pensare al design dell'algoritmo. Questo è spesso molto utile.
I metodi di memorizzazione e bottom-up offrono una regola / metodo per trasformare le relazioni di ricorrenza in codice. La memorizzazione è un'idea relativamente semplice, ma spesso le idee migliori lo sono!
La programmazione dinamica ti offre un modo strutturato di pensare al tempo di esecuzione del tuo algoritmo. Il tempo di esecuzione è sostanzialmente determinato da due numeri: il numero di sottoproblemi che devi risolvere e il tempo necessario per risolvere ogni sottoproblema. Ciò fornisce un modo semplice e conveniente per pensare al problema di progettazione dell'algoritmo. Quando hai una relazione di ricorrenza candidata, puoi guardarla e capire molto rapidamente quale potrebbe essere il tempo di esecuzione (ad esempio, spesso puoi dire molto rapidamente quanti sottoproblemi ci saranno, che è un limite inferiore al tempo di esecuzione; se ci sono molti sottoproblemi in modo esponenziale che devi risolvere, probabilmente la ricorrenza non sarà un buon approccio). Ciò consente anche di escludere le decomposizioni dei sottoproblemi candidati. Ad esempio, se abbiamo una stringaS [ 1 .. i ] S [ j . . n ] S [ i . . j ] n S nS[ 1 .. n ], definire un sottoproblema con un prefisso o suffisso o sottostringa potrebbe essere ragionevole (il numero di sottoproblemi è polinomiale in ), ma definire un sottoproblema da una sottosequenza di non è probabile che sia un buon approccio (il numero di sottoproblemi è esponenziale in ). Ciò consente di eliminare lo "spazio di ricerca" di possibili ricorrenze.S[ 1 .. i ]S[ j . . n ]S[ i . . j ]nSn
La programmazione dinamica ti offre un approccio strutturato per cercare le relazioni di ricorrenza del candidato. Empiricamente, questo approccio è spesso efficace. In particolare, ci sono alcune euristiche / schemi comuni che puoi riconoscere per modi comuni di definire i sottoproblemi, a seconda del tipo di input. Per esempio:
Se l'input è un numero intero positivo , un modo candidato per definire un sottoproblema è sostituendo con un numero intero più piccolo (st ).n n ′ 0 ≤ n ′ ≤ nnnn′0≤n′≤n
Se l'input è una stringa , alcuni modi candidati per definire un sottoproblema includono: sostituire con un prefisso ; sostituire con un suffisso ; sostituire con una sottostringa . (Qui il sottoproblema è determinato dalla scelta di .)S [ 1 .. n ] S [ 1 .. i ] S [ 1 .. n ] S [ j . . n ] S [ 1 .. n ] S [ i . . j ] i , jS[1..n]S[1..n]S[1..i]S[1..n]S[j..n]S[1..n]S[i..j]i,j
Se l'input è un elenco , fai lo stesso che faresti per una stringa.
Se l'input è un albero , un modo candidato per definire un sottoproblema è sostituire con qualsiasi sottostruttura di (cioè, selezionare un nodo e sostituire con la sottostruttura radicata in ; il sottoproblema è determinato dalla scelta di ).T T x T x xTTTxTxx
Se l'input è una coppia , guarda ricorsivamente il tipo di e il tipo di per identificare un modo per scegliere un sottoproblema per ciascuno. In altre parole, un modo per definire un candidato sottoproblema è quello di sostituire da dove è un sottoproblemi per ed è un sottoproblemi per . (Puoi anche considerare i sottoproblemi del modulo o .)x y ( x , y ) ( x ′ , y ′ ) x ′ x y ′ y ( x , y ′ ) ( x ′ , y )(x,y)xy(x,y)(x′,y′)x′xy′y(x,y′)(x′,y)
E così via. Questo ti dà un'euristica molto utile: semplicemente guardando la firma del tipo del metodo, puoi trovare un elenco di modi candidati per definire i sottoproblemi. In altre parole, semplicemente osservando la dichiarazione del problema - osservando solo i tipi di input - puoi trovare una manciata di modi candidati per definire un sottoproblema.
Questo è spesso molto utile. Non ti dice quale sia la relazione di ricorrenza, ma quando hai una scelta particolare su come definire il sottoproblema, spesso non è troppo difficile elaborare una relazione di ricorrenza corrispondente. Quindi, spesso trasforma la progettazione di un algoritmo di programmazione dinamica in un'esperienza strutturata. Annoti su carta straccia un elenco di modi candidati per definire i sottoproblemi (usando l'euristica sopra). Quindi, per ciascun candidato, si tenta di annotare una relazione di ricorrenza e di valutarne il tempo di esecuzione contando il numero di sottoproblemi e il tempo trascorso per sottoproblema. Dopo aver provato ogni candidato, mantieni il migliore che sei riuscito a trovare. Fornire una struttura al processo di progettazione dell'algoritmo è di grande aiuto, poiché altrimenti la progettazione dell'algoritmo può essere intimidatoria (