320 likes | 461 Views
Algoritmi e Struttur e Dati (Mod. B). Programmazione Dinamica (Parte III). Sottosequenza. Una sequenza S’= ( a 1 ,…,a m ) è una sotto-sequenza della sequenza S se S’ è ottenuta da S rimuovendo uno o più elementi .
E N D
Algoritmi e Strutture Dati (Mod. B) Programmazione Dinamica (Parte III)
Sottosequenza Una sequenza S’=(a1,…,am) è una sotto-sequenza della sequenza Sse S’ è ottenuta da Srimuovendo uno o più elementi. Gli elementi rimanenti devono comparire nello stesso ordinenella sequenza risultante, anche se non devono essere necessariamente conti-gui in S. • La sequenza nulla (di lunghezza0) è una sottosequenza di ogni sequenza. • Una sequenza è una lista di elementi ma…. • … una sottosequenza non è necessariamente una sottolista (poiché deve essere contigua).
Sottosequenza più lunga comune Definizione: Date due sequenze S1=(a1,…,am) e S2=(b1,…,bn), una sottosequenza comune Z di S1 e S2 è una sequenza che è sottosequenza di entrambe le sequenze S1e S2. Definizione: Date due sequenze S1=(a1,…,am) e S2=(b1,…,bn), la più lunga sottosequenza comune Z (LCS) di S1e S2 è la sottosequenza comune di S1e S2 che ha lungezza massima.
LCS[S1,S2] = AAATA Sottosequenza più lunga comune • Input • 2 sequenze di simboli, S1 e S2 • Output • Trovare la più lunga sottosequenza comune (LCS) di S1 e S2 Esempio S1 = AAAATTGAS2 = TAACGATA
Soluzione esaustiva LCS-Esaustivo(X[],Y[]: array di char) l=0 LCS=Nil /* Enumera tutte le sottosequenza di X */ for each “sottosequenza K di X” do if “K è una sottosequenza di Y” then ls=lunghezza[K] if ls>l then l=ls LCS=K return LCS Miglioramento possibile: Se lunghezza[Y]<lunghezza[X] enumera solo le sotto-sequenze di lunghezza minore o uguale a lunghezza[Y].
Soluzione impraticabile! Soluzione esaustiva Ma data una sequenza di lunghezza n, quante sono le possibili sottosequenze? Ogni sottosequenza può avere lunghezza k con 0kn. Cioè il numero di sottosequenze è pari al numero di possibili sottoinsiemi di elementi distinti di un insieme degli n elementi nella sequenza originaria
Carattedizzazione della soluzione ottima Iniziamo col caratterrizzare la struttura della soluzione ottima. Data una sequenza X=(x1,…,xn), denoteremo con Xi, l’i-esimo prefisso di X, cioè la sotto-sequenza (x1,…,xi). X0 denota la sotto-sequenza nulla. Esempio: • X = ABDCCAABD • X3= ABD • X6= ABDCCA
X[1,…,m-1] X[1,…,m] X Y[1,…,n] Y[1,…,n-1] X Z[1,…,k] Z[1,…,k-1] X X[1,…,m-1] X[1,…,m] X Y[1,…,n] Y[1,…,n] Y Y Z[1,…,k] Z[1,…,k] ? ? X[1,…,m] X[1,…,m] X X Y[1,…,n] Y[1,…,n-1] Y Z[1,…,k] Z[1,…,k] ? ? 1) xm= yn 2) xm yne zk xm 3) xm yne zk ym
Carattedizzazione della soluzione ottima Teorema:Date le due sequenze X=(x1,…,xm) e Y=(y1,…,yn), sia Z=(z1,…,zk) una LCS di X e Y. • se xm= yn, allora zk = xn = yne Zk-1è una LCS di Xm-1e Yn-1. • se xm yne zk xm, allora Zè una LCS di Xm-1e Y. • se xmyn e zk yn, allora Zè una LCS di Xe Yn-1.
Carattedizzazione della soluzione ottima Teorema:Date le due sequenze X=(x1,…,xm) e Y=(y1,…,yn), sia Z=(z1,…,zk) una LCS di X e Y. • se xm= yn, allora zk = xm = yne Zk-1è una LCS di Xm-1e Yn-1. • se xm yne zk xm, allora Zè una LCS di Xm-1e Y. • se xmyn e zk yn, allora Zè una LCS di Xe Yn-1. Dimostrazione: • Suponiamo xm= yn ma zk xm. Poiché Z è una sottosequenza comune diX eYdi lunghezza k, Ma allora concatenando xm a Z otterremmo una sotto-sequenza comune diXeY di lunghezza k+1. Questo però contraddice l’assunzione che Z sia una LCS diXeY. Quindi deve essere zk =xm =yn
Carattedizzazione della soluzione ottima Teorema:Date le due sequenze X=(x1,…,xm) e Y=(y1,…,yn), sia Z=(z1,…,zk) una LCS di X e Y. • se xm= yn, allora zk = xm = yne Zk-1è una LCS di Xm-1e Yn-1. • se xm yne zk xm, allora Zè una LCS di Xm-1e Y. • se xmyn e zk yn, allora Zè una LCS di Xe Yn-1. Dimostrazione: Quindi deve essere zk =xm =yn Ma allora eliminando dalle 3 sequenze l’ultimo carattere, otteniamo che Zk-1 deve essere una sottosequenza comune di Xm-1 e Yn-1 di lunghezza k-1 Ma Zk-1 è anche una LCS di Xm-1 e Yn-1? (Per assurdo) Supponiamo che esista una sottosequenza comuneW di Xm-1 e Yn-1 di lunghezza maggiore di k-1. Allora concatenando zk a Wotterremmo ancora una sotto-sequenza comune più lunga di Z, contraddicendo l’ipotesi.
Carattedizzazione della soluzione ottima Teorema:Date le due sequenze X=(x1,…,xm) e Y=(y1,…,yn), sia Z=(z1,…,zk) una LCS di X e Y. • se xm= yn, allora zk = xm = yne Zk-1è una LCS di Xm-1e Yn-1. • se xm yne zk xm, allora Zè una LCS di Xm-1e Y. • se xmyn e zk yn, allora Zè una LCS di Xe Yn-1. Dimostrazione: • Se xm yne zk xm, allora Zè una LCSdi Xm-1e Yn Infatti, se esistesse una sottosequenza comuneW di Xm-1e Y di lunghezza maggiore di k, allora (essendo xm yne zk xm) W sarebbe pure una sottosequenza comune di Xme Y. Ma questo contraddice l’ipotesi che Z sia una LCS di X e Y. • Se xm yne zk ym, allora Zè una LCSdi Xe Yn-1 La dimostrazione è simmetrica a quella del punto 2
Definizione ricorsiva della soluzione ottima • c(i,j) =lunghezza della LCSdi Xi e Yj. • Vogliamo trovare c(m,n) dove m e n sono le lunghezze di X e Y, rispettivamente. c(i,j) = 0 se i=0 o j=0 c(i,j) = ? se i,j 0
1) xm= yn X[1,…,i-1] X[1,…,i] X Y[1,…,j] Y[1,…,j-1] X Z[1,…,k] Z[1,…,k-1] X 2) xm yne zk xm X[1,…,i-1] X[1,…,i] X Y[1,…,j] Y[1,…,j] Y Y Z[1,…,k] Z[1,…,k] ? ? 3) xm yne zk ym X[1,…,i] X[1,…,i] X X Y[1,…,j] Y[1,…,j-1] Y Z[1,…,k] Z[1,…,k] ? ? c(i,j) = c(i-1,j-1) + 1 se i,j > 0 e xi = yj c(i,j) = max { c(i-1,j), c(i,j-1) } se i,j > 0 e xi yj
Definizione ricorsiva della soluzione ottima • c(i,j) =lunghezza della LCSdi Xi e Yj. • Vogliamo trovare c(m,n) dove m e n sono le lunghezze di X e Y, rispettivamente.
Definizione ricorsiva della soluzione ottima RLCS-length(X[]Y[]:array of char;i,j:intero) ifi=0orj=0 then return 0 else ifX[i]Y[j] then return max(RLCS-length(X,Y,i,j-1), RLCS-length(X,Y,i -1,j)) else return 1+RLCS-length(b,X,i-1,j-1)
i-1,j i,j-1 i-2,j i-1,j-1 i,j-2 i-1,j-1 i-1,j-2 i-2,j-2 i-1,j-2 i-2,j-1 i-2,j-1 i-3,j i,j-3 i-1,j-2 i-2,j-2 i-1,j-3 i-1,j-3 i-2,j-2 i-3,j-1 i-2,j-2 Definizione ricorsiva della soluzione ottima i,j
Calcolo del valore della soluzione ottima Utilizziamo due tabelle di dimensione mn • c[i,j] conterrà il valore della lunghezza della massima sottosequenza comune dei prefissi Xie Yj. • c[m,n] conterrà quindi lunghezza della massima sottosequenza comunedi Xe Y. • b[i,j] conterrà un “puntatore” alla entry della tabella stessa che identifica il sottoproblema ottimo scelto durante il calcolo del valore c[i,j]. • i valori possibili saranno , e
Calcolo del valore della soluzione ottima Utilizziamo due tabelle di dimensione mn • b[i,j] conterrà un “puntatore” alla entry della tabella stessa che identifica il sottoproblema ottimo scelto durante il calcolo del valore c[i,j]. • i valori possibili saranno , e • punta alla cella con indicii-1,j-1 • punta alla cella con indicii-1,j • punta alla cella con indicii,j-1
0 1 2 3 4 5 6 j i A T B C B D 0 0 0 0 0 0 0 0 1 T 0 0 1 1 1 1 1 2 A 0 1 1 1 1 1 1 3 C 0 1 1 1 2 2 2 4 C 0 1 1 1 2 2 2 5 B 0 1 1 2 2 3 3 6 T 0 1 2 2 2 3 3 • TACCBT • ATBCBD punta ai-1,j-1 punta ai-1,j punta ai,j-1 c(i,j) = 0 se i=0 o j=0 c(i,j) = c(i-1,j-1) + 1 se i,j > 0 e xi = yj c(i,j) = max{ c(i-1,j), c(i,j-1) } se i,j > 0 e xi yj
j i 0 1 2 3 4 5 6 B E B E D E 0 0 0 0 0 0 0 0 1 A 0 0 0 0 0 0 0 2 B 1 1 1 1 1 1 0 3 D 1 1 1 1 2 2 0 4 D 1 1 1 1 2 2 0 5 B 1 1 2 2 2 2 0 6 E 1 2 2 3 3 3 0 • ABDDBE • BEBEDE punta ai-1,j-1 punta ai-1,j punta ai,j-1 c(i,j) = 0 se i=0 o j=0 c(i,j) = c(i-1,j-1) + 1 se i,j > 0 e xi = yj c(i,j) = max{ c(i-1,j), c(i,j-1) } se i,j > 0 e xi yj
Inizalizzazione prima riga e prima colonna della marice I carattri finali di Xj e Yj sono identici! • I caratteri finali diversi • LCS di Xj-1 e Yj è non peggiore • LCS di Xj e Yj -1 è migliore Calcolo del valore della soluzione ottima LCS-Length(X[],Y[]: array of char) m=lunghezza[X] n=lunghezza[Y] for i=1 to m do c[i,0]=0 for j=1 to n do c[0,j]=0 for i=1 to m do for j=1 to n do if xi=yj then c[i,j]=1+c[i-1,j-1] b[i,j]=“” else ifc[i-1,j]c[i,j-1] then c[i,j]=c[i-1,j] b[i,j]=“” else c[i,j]=c[i,j-1] b[i,j]=“” returnbec
(m+n) (n) (nm) Calcolo del valore della soluzione ottima LCS-Length(X[],Y[]: array of char) m=lunghezza[X] n=lunghezza[Y] for i=1 to m do c[i,0]=0 for j=1 to n do c[0,j]=0 for i=1 to m do for j=1 to n do if xi=yj then c[i,j]=1+c[i-1,j-1] b[i,j]=“” else ifc[i-1,j]c[i,j-1] then c[i,j]=c[i-1,j] b[i,j]=“” else c[i,j]=c[i,j-1] b[i,j]=“” returnbec
Costruzione della soluzione ottima Per costruire la LCS possiamo quindi utilizzare la tabella b[i,j] che contiene i “puntatori” ai sottoproblemi ottimi per ogni coppia di indici i e j. Partiamo dalla entry b[m,n] e procediamo a ritroso seguendo le “frecce” della tabella. Ricordate che LCS-Length assegna b[i,j] = solo quando xi= yj . Quindi, partendo dalla fine della tabella, ogni volta che in b[i,j] troviamo sappiamo che xi(=yj) è contenuto nella LCS che cerchiamo. I valori vengono stampati nell’ordine corretto.
Costruzione della soluzione ottima Print-LCS(b[]: array;X[]: array;i,j: intero) ifi = 0orj = 0 then return ifb[i,j] = ”” then Print-LCS(b,X,i-1,j-1) print xi else if b[i,j] = ”” then Print-LCS(b,X,i-1,j) else Print-LCS(b,X,i,j-1)
0 1 2 3 4 5 6 j i A T B C B D 0 0 0 0 0 0 0 0 1 T 0 0 1 1 1 1 1 2 A 0 1 1 1 1 1 1 3 C 0 1 1 1 2 2 2 4 C 0 1 1 1 2 2 2 5 B 0 1 1 2 2 3 3 6 T 0 1 2 2 2 3 3 • TACCBT • ATBCBD c(i,j) = 0 se i=0 o j=0 c(i,j) = c(i-1,j-1) + 1 se i,j > 0 e xi = yj c(i,j) = max{ c(i-1,j), c(i,j-1) } se i,j > 0 e xi yj
j i T C B • TCB 0 1 2 3 4 5 6 • TACCBT • ATBCBD A T B C B D 0 0 0 0 0 0 0 0 1 T 1 0 1 1 1 1 0 2 A 1 1 1 1 1 1 0 3 C 2 1 1 1 2 2 0 4 C 0 1 1 1 2 2 2 5 B 3 0 1 1 2 2 3 6 T 0 1 2 2 2 3 3 c(i,j) = 0 se i=0 o j=0 c(i,j) = c(i-1,j-1) + 1 se i,j > 0 e xi = yj c(i,j) = max{ c(i-1,j), c(i,j-1) } se i,j > 0 e xi yj
j i 0 1 2 3 4 5 6 B E B E D E 0 0 0 0 0 0 0 0 1 A 0 0 0 0 0 0 0 2 B 1 1 1 1 1 1 0 3 D 1 1 1 1 2 2 0 4 D 1 1 1 1 2 2 0 5 B 1 1 2 2 2 2 0 6 E 1 2 2 3 3 3 0 • ABDDBE • BEBEDE c(i,j) = 0 se i=0 o j=0 c(i,j) = c(i-1,j-1) + 1 se i,j > 0 e xi = yj c(i,j) = max{ c(i-1,j), c(i,j-1) } se i,j > 0 e xi yj
B D E • BDE • ABDDBE • BEBEDE j i 0 1 2 3 4 5 6 B E B E D E 0 0 0 0 0 0 0 0 1 A 0 0 0 0 0 0 0 2 B 0 1 1 1 1 1 1 3 D 0 1 1 1 1 2 2 4 D 0 1 1 1 1 2 2 5 B 0 1 1 2 2 2 2 6 E 1 2 2 3 3 3 0 c(i,j) = 0 se i=0 o j=0 c(i,j) = c(i-1,j-1) + 1 se i,j > 0 e xi = yj c(i,j) = max{ c(i-1,j), c(i,j-1) } se i,j > 0 e xi yj
Costruzione della soluzione ottima Print-LCS(b[]: array;X[]: array;i,j: intero) ifi = 0orj = 0 then return ifb[i,j] = ”” then Print-LCS(b,X,i-1,j-1) print xi else if b[i,j] = ”” then Print-LCS(b,X,i-1,j) else Print-LCS(b,X,i,j-1) Poiché ad ogni passo della ricorsione almeno uno tra i e jviene decrementato, il tempo di esecuzione è pari alla somma delle lunghezze delle due sequenze: (m+n)
Ottimizzazioni possibili • La tabella b[i,j] può essere eliminata, risparmia-ndo un . Il valore di c[i,j] dipende solo dai valori c[i-1,j-1], c[i,j-1] e c[i-1,j]. In tempo costante si può quindi determinare quale di questi tre è stato usato, e perchò quale sia il tipo di freccia. (Esercizio 16.3-2) • Se ci serve solo calcolare la lunghezza della LCS, possiamo ancora ridurre lo spazio della tabella c[i,j] a due sole righe di lunghezza min{ n , m } Ad ogni istante (cioè per ogni coppia i,j), ci servono i valori c[i-1,j-1], c[i,j-1] e c[i-1,j], che stanno nella riga corrente e in quella precedente. (Esercizio 16.3-4)
Esercizi Esercizi: • 16.3-2 • 16.3-3 • 16.3-4 Problemi: • 16.2 • 16.3 • 16.4