TD d’algorithmique avanc´ee
Corrig´e du TD 5 : plus longue sous-s´equence commune
Jean-Michel Dischler et Fr´ ed´ eric Vivien
Probl´ ematique
Une s´equence est une suite finie de symboles pris dans un ensemble fini. Si u=ha1, a2, ..., ani est une s´equence, o`ua1,a2, ...,an sont des lettres, l’entiernest lalongueur deu. Une s´equence v=hb1, b2, ..., bmi est une sous-s´equence de u = ha1, a2, ..., ani s’il existe des entiers i1, i2, ..., im (1 ≤ i1 < i2 < ... <
im ≤ n) tels que bk = aik pour k ∈ [1, m]. Par exemple, v = hB, C, D, Bi est une sous-s´equence de u=hA, B, C, B, D, A, Bicorrespondant `a la suite d’indiceh2,3,5,7i.
Une s´equencewest unesous-s´equence communeaux s´equencesuetvsiwest une sous-s´equence deuet dev. Une sous-s´equence commune estmaximaleou est uneplus longue sous-s´equence si elle est de longueur maximale. Par exemple : les s´equences hB, C, B, Ai et hB, D, A, Bi sont des plus longues sous-s´equences communes dehA, B, C, B, D, A, Biet de hB, D, C, A, B, Ai.
R´ esolution par programmation dynamique
1. On cherche `a d´eterminer la longueur d’une sous-s´equence commune maximale `a u=ha1, a2, ..., aniet v=hb1, b2, ..., bmi. On noteL(i, j) la longueur d’une sous-s´equence commune maximale `aha1, a2, ..., aii et hb1, b2, ..., bji (0 ≤ j ≤m, 0 ≤i ≤n). Donnez une r´ecurrence d´efinissant L(i, j). Indication : on pourra distinguer les cas ai =bj etai6=bj.
L(i, j) =
0 sii= 0 ouj= 0,
1 +L(i−1, j−1) sinon et siai =bj, max(L(i, j−1), L(i−1, j)) sinon.
(1)
En effet, si ai6=bj, une plus longue sous-s´equence commune deha1, a2, ..., aiiethb1, b2, ..., bjine peut pas se terminer par une lettre c´egale `aai et `abj, et donc une plus longue sous-s´equence commune – soit ne se termine pas parai et elle est alors une plus longue sous-s´equence commune des s´equences
ha1, a2, ..., ai−1iethb1, b2, ..., bji, et est de longueur L(i−1, j);
– soit ne se termine pas parbj et elle est alors une plus longue sous-s´equence commune des s´equences ha1, a2, ..., aiiethb1, b2, ..., bj−1i, et est de longueur L(i, j−1).
Si, par contre, ai =bj, alors une plus longue sous-s´equence commune deha1, a2, ..., aiiethb1, b2, ..., bji se termine par ai =bj (sinon on peut la rallonger parai) et son pr´efixe (la sous-s´equence moins son dernier ´el´ement) est une plus longue sous-s´equence commune deha1, a2, ..., ai−1iethb1, b2, ..., bj−1i. 2. ´Ecrivez alors un algorithme r´ecursif calculant la longueur de la plus longue sous-s´equence commune de
deux s´equences.
PLSSC-R´ecursif(A,i,B, j) sii= 0 ouj= 0
alors renvoyer0 sinon siA[i] =B[j]
alors renvoyer1+PLSSC-R´ecursif(A,i−1,B,j−1)
sinon renvoyermax(PLSSC-R´ecursif(A,i−1,B, j),PLSSC-R´ecursif(A,i, B,j−1)) 3. Montrez que cet algorithme est de complexit´e au moins exponentielle dans le cas o`u les deux s´equences
n’ont pas d’´el´ements en commun.
1
Dans ce cas, on se trouve toujours dans le troisi`eme cas de l’´equation 1 et la complexit´e est d´efinie par la r´ecurrence :
T(n, m) =
0 sin= 0oum= 0, T(n, m−1) +T(n−1, m) sinon.
D’o`u T(n, m) =T(n, m−1) +T(n−1, m)
= (T(n, m−2) +T(n−1, m−1)) + (T(n−1, m−1) +T(n−2, m−1))
≥2T(n−1, m−1).
Donc T(n, m) = Ω(2min(m,n)).
4. ´Ecrivez alors un algorithme suivant le paradigme de la programmation dynamique et calculant la longueur de la plus longue sous-s´equence commune de deux s´equences.
PLSSC-ProgDyn(A, B) n←longueur(A) m←longueur(B)
pouri←1`a nfaire l[i,0]←0 pourj ←1`am fairel[0, j]←0 pouri←1`a nfaire
pourj←1 `amfaire siA[i] =B[j]
alorsl[i, j]←1 +l[i−1, j−1]
sinon l[i, j]←max(l[i−1, j], l[i, j−1]) renvoyerl[n, m]
5. Quelle est la complexit´e de cet algorithme ?
La complexit´e est due aux deux boucles imbriqu´ees :T(n, m) =O(nm).
6. Modifiez l’algorithme pr´ec´edent pour que l’on puisse en plus construireune plus longue sous-s´equence commune et affichez une telle sous-s´equence.
PLSSC-ProgDyn(A, B) n←longueur(A) m←longueur(B)
pouri←1`a nfaire l[i,0]←0 pourj ←1`am fairel[0, j]←0 pouri←1`a nfaire
pourj←1 `amfaire siA[i] =B[j]
alorsl[i, j]←1 +l[i−1, j−1]
s[i, j]←«=»
sinon sil[i−1, j]> l[i, j−1]) alorsl[i, j]←l[i−1, j]
s[i, j]←«←» sinonl[i, j]←l[i, j−1]
s[i, j]←«→» renvoyerl[n, m] ets
Affichage-PLSC(s, A,i,j) sii= 0 ouj= 0alors renvoyer sis[i, j] =«=»
alorsAffichage-PLSC(s,A,i−1,j−1) affiche A[i]
sinon sis[i, j] =«←»alorsAffichage-PLSC(s,A,i−1,j) sis[i, j] =«→»alorsAffichage-PLSC(s,A,i,j−1)
On appelle initialementPLSSC-ProgDyn(A,B) puis Affichage-PLSC(s,A,n,m).
2