PM-04 p. 1/18 Programozási módszertan Dinamikus programozás: Nyomtatási feladat A leghosszabb közös részsorozat Werner Ágnes Villamosmérnöki és Információs Rendszerek Tanszék e-mail: werner.agnes@virt.uni-pannon.hu
PM-04 p. 2/18 Dinamikus programozás jellemzői Egy dinamikus programozási algoritmus kifejlesztése 4 lépésre bontható fel: 1. Jellemezzük az optimális megoldás szerkezetét. 2. Rekurzív módon definiáljuk az optimális megoldás értékét. 3. Kiszámítjuk az optimális megoldás értékét alulról felfelé történő módon. 4. A kiszámított információk alapján megszerkesztünk egy optimális megoldást.
PM-04 p. 3/18 Nyomtatási feladat Feladat az s 1,s 2,...,s n szavakból álló bekezdés kinyomtatása. A szavak rendre l 1,l 2,...,l n karakterekből állnak. A nyomtató egy sorba összesen M karaktert tud elhelyezni. Tegyük fel, hogy l i M 1 i n esetén. Ha egy sor az s i -től s j -ig terjedő szavakat tartalmazza, akkor a szavak között mindig egy szóköz van, míg a sor végén további M j + i j m=i l m extra szóköz (nem negatív!). Adjunk meg egy hatékony algoritmust, amely a "legszebben" nyomtatja ki a bekezdést, azaz minimalizálja az utolsó sor kivételével a sorok végén található extra szóközök számának köbeinek összegét!
PM-04 p. 4/18 Megoldás dinamikus programozással 1 i j n esetén legyen e[i,j] = M j + i j m=i l m (az s i -től s j -ig terjedő szavakat tartalmazó sor végén lévő extra szóközök száma) 1 i j n esetén legyen k[i, j] =, ha e[i,j] < 0, 0, ha j = n és e[i,j] 0, e[i,j] 3, különben
PM-04 p. 5/18 Megoldás dinamikus programozással Tekintsük az s 1,s 2,...,s j szavak egy optimális elrendezését. Tegyük fel, hogy ebben az utolsó sor az s i szóval kezdődik. Vegyük észre, hogy ekkor az utolsó előtti sorig terjedő rész az s 1,s 2,...,s i 1 szavak egy optimális elrendezése. Ha nem így lenne, akkor ezt a részt lecserélve az s 1,s 2,...,s i 1 szavak egy optimális elrendezésére az s 1,s 2,...,s j szavak egy "szebb" elrendezéséhez jutnánk, ami ellentmondás. Jelölje c[j] az s 1,s 2,...,s j szavak optimális elrendezésének soraihoz rendelt k értékek összegét. c[j] = { 0, ha j = 0, min{c[i 1] + k[i,j] 1 i j}, ha j > 0. 1 i j estén legyen p[j] annak az s i szónak az indexe, amellyel az utolsó sor kezdődik az s 1,s 2,...,s j szavak optimális elrendezésénél.
PM-04 p. 6/18 Program 1. Nyomtatás(l,n,M) 2. for i = 1 to n do 3. e[i, i] = M l[i] 4. for j = i + 1 to n do 5. e[i, j] = e[i, j 1] l[j] 1 6. for i = 1 to n do 7. for j = i to n do 8. if e[i, j] < 0 9. then k[i, j] = 10. else 11. if j = n and e[i, j] 0 12. then k[i, j] = 0 13. else k[i, j] = e[i, j] 3 14. c[0] = 0 15. for j = 1 to n do 16. c[j] = 17. for i = 1 to j do 18. if c[i 1] + k[i, j] < c[j] then 19. c[j] = c[i 1] + k[i, j]; p[j] = i 21. return c, p
PM-04 p. 7/18 Tördelés 1. Tördelés(p,j) 2. i = p[j] 3. if i = 1 4. then h = 1 5. else h = Trdels(p,i 1) + 1 6. print (h,i,j) 7. return h Az eljárás az optimálisan tördelt bekezdés sorainak számával tér vissza. A kinyomtatott (h,i,j) hármasok azt mutatják, hogy a h-adik sor az s i -től s j -ig terjedő szavakat tartalmazza (h = 1,2,...). A Nyomtatás eljárás költsége O(n 2 ), a Tördelés eljárás költsége O(n).
PM-04 p. 8/18 Bevezetés Biológiai alkalmazásokban gyakran össze kell hasonlítani pl. két vagy több élőlény DNS-ét. A DNS-t bizonyos, bázisnak nevezett molekulák szekvenciái alkotják. A lehetséges bázisok: adenin, guanin, citozin és timin. A bázisokat a kezdőbetűjükkel jelöljük. A DNS szerkezete leírható a véges [A, C, G, T] halmazon vett sztringgel. Pl. az egyik élőlény DNS-e S 1 = ACCGGTCGAGTGCGCGGAAGCCGGCCGAA a másik élőlény DNS-e S 2 = GTCGTTCGGAATGCCGTTGCTCTGTAAA Két élőlény DNS-ét pl. abból a célból hasonlíthatjuk össze, hogy megállapítsuk, hogy mennyire hasonlóak. (valamilyen mérték szerint a két lény mennyire közel áll egymáshoz)
PM-04 p. 9/18 Összehasonlítás A hasonlóságot több féle képpen definiálhatjuk: két DNS szekvencia hasonló, ha az egyik a másiknak részsztringje, két szekvencia hasonló, ha kevés változtatással vihetők át egymásba, keresünk egy olyan S 3 szekvenciát, amelyik olyan bázisokból áll, amelyek ugyanabban a sorrendben, de nem feltétlenül egymás után fordulnak elő mind S 1 -ben, mind S 2 -ben; minél hosszabb, annál nagyobb a hasonlóság. A példában: a leghosszabb S3 szekvencia S 1 = ACCGGTCGAGTGCGCGGAAGCCGGCCGAA S 2 = GTCGTTCGGAATGCCGTTGCTCTGTAAA S 3 = GTCGTCGGAAGCCGGCCGAA
PM-04 p. 10/18 Részsorozat, közösrészsorozat Egy sorozat részsorozata egy olyan sorozat, amit az adott sorozatból néhány elem elhagyásával nyerünk. Formálisan: Ha az adott X = (x 1,x 2,...,x m ), akkor egy másik sorozat Z = (z 1,z 2,...,z k ) sorozat akkor részsorozata X-nek, ha létezik X indexeinek egy szigorúan növő (i 1,i 2,...,i k ) sorozata, hogy minden j = 1,2,...,k esetén x ij = z j. Adott két sorozat, X és Y. Azt mondjuk, hogy egy Z sorozat közös részsorozatuk, ha Z részsorozata X-nek is és Y -nak is.
PM-04 p. 11/18 A leghosszabb közös részsorozat=lkr 1. lépés: A leghosszabb közös részsorozat jellemzése A feladat megoldásának egyik módszere leszámolni X összes részsorozatát és mindegyiket ellenőrizni, hogy részsorozata-e Y -nak és tárolnunk kell a megtalált leghosszabb részsorozatot. X mindegyik részsorozata az 1,2,...,m indexhalmaz egy részhalmazának felel meg. Mivel X-nek 2 m részsorozata van, az eljárás exponenciális időt igényel. Az algoritmus használhatatlan. Ez a probléma azonban rendelkezik az optimális részstruktúra tulajdonsággal.
PM-04 p. 12/18 Az LKR optimális részstruktúrája Az X = (x 1,x 2,...,x m ) sorozat i-edik prefixe X i = (x 1,x 2,...,x i ) (i = 0,1,...,m). Tétel: (Az LKR optimális részstruktúrája.) Legyen X = (x 1,x 2,...,x m ) és Y = (y 1,y 2,...,y n ) két sorozat és Z = (z 1,z 2,...,z k ) ezek egy LKR-je. Ekkor igazak a következő állítások: 1. Ha x m = y n, akkor z k = x m = y n és Z k 1 az X m 1 és Y n 1 egy LKR-je. 2. Ha x m y n, akkor z k x m esetén Z az X m 1 és Y egy LKR-je. 3. Ha x m y n, akkor z k y n és Z az X és Y n 1 egy LKR-je.
PM-04 p. 13/18 Az LKR optimális részstruktúrája Bizonyítás: 1. Ha z k x m, akkor az x m = y n elemet hozzátehetnénk Z-hez, és így X és Y egy k + 1 hosszú közös részsorozatát kapnánk, ez ellentmond Z választásának. Ezért z k = x m = y n. Most a Z k 1 prefix hossza k 1 és közös részsorozata X m 1 -nek és Y n 1 -nek. Meg kell mutatni, hogy ezek egy LKR-je is. Ha W egy legalább k hosszú közös részsorozata X m 1 -nek és Y n 1 -nek, akkor ehhez hozzáfűzve az x m = y n elemet, X és Y k-nál hosszabb közös részsorozatát kapjuk, ami ellentmond Z választásának. 2. Ha z k x m, akkor Z közös részsorozata X m 1 -nek és Y -nak. Ha ezeknek volna egy W közös részsorozata, mely hosszabb, mint k, akkor ez közös részsorozata volna X m -nek és Y -nak, ami ismét ellentmond Z választásának. 3. A bizonyítás hasonlóan történik, mint 2-nél.
PM-04 p. 14/18 2. lépés: részfeladatok rekurzív megoldása A tétel azt mondja, hogy csak egy vagy kettő részfeladat van, amit meg kell vizsgálni X = (x 1, x 2,..., x m ) és Y = (y 1, y 2,..., y n ) LKR-jének megkeresésekor. Ha xm = y n, akkor X m 1 és Y n 1 LKR-jét kell megkeresni, amelyhez csatolva az x m = y n elemet kapjuk X és Y LKR-jét. Ha xm y n, akkor két részfeladatot kell megoldanunk: X m 1 és Y, illetve X és Y n 1 LKR-jét kell megkeresni. Akármelyik is a hosszabb, az az X és Y LKR-je. Mivel ezek az esetek kimerítik az összes lehetőséget, tudjuk, hogy egy részfeladat megoldása benne van X és Y LKR-jében. Látható, hogy az LKR problémában a részfeladatok átfedők. X és Y LKR-jének megkeresésekor szükségünk lehet X és Yn 1, illetve X m 1 és Y LKR-jének megkeresésére. Ezek közös részfeladata Xm 1 és Y n 1 LKR-jének meghatározása.
PM-04 p. 15/18 Rekurzív összefüggés Meghatározható egy rekurzív összefüggés: Legyen c[i,j] X i és Y j LKR-jének hossza. Ha akár i, akár j nulla, azaz a sorozatok legalább egyikének hossza 0, akkor természetesen az LKR hossza is 0. Az LKR optimális részstruktúra tulajdonságából a következő rekurzív képletet kapjuk: c[i, j] = 0, ha i = 0 vagyj = 0, c[i 1,j 1] + 1, ha i,j > 0 és x i = y j max(c[i,j 1],c[i 1,j]), ha i,j > 0 és x i y j
PM-04 p. 16/18 3. lépés: LKR hosszának kiszámítása Használhatjuk a dinamikus programozást. LKR-hossza(X, Y ) 1. m := hossz[x] 2. n := hossz[y ] 3. for i := 1 to m do c[i,0] := 0 4. for j := 1 to n do c[0, j] := 0 5. for i := 1 to m 6. do for j := 1 to n 7. do if x i = y j 8. then c[i, j] := c[i 1, j 1] + 1 9. b[i, j] := 10. else if c[i 1, j] c[i, j 1] 11. then c[i, j] := c[i 1, j] b[i, j] := 12. else c[i, j] := c[i, j 1] b[i, j] := 13. return c és b Az eljárás futási ideje O(m n), mivel minden tömbelem kiszámításának ideje O(1).
Eredmény mátrix PM-04 p. 17/18
PM-04 p. 18/18 4.lépés: Egy LKR megszerkesztése Az alábbi eljárás X és Y LKR-jének elemeit a helyes, eredeti sorrendben nyomtatja ki. LKR-nyomtat(b, X, i, j) 1. if i = 0 vagy j = 0 2. then return 3. if b[i,j] = 4. then LKR-nyomtat(b,X,i 1,j 1) 5. print x i 6. else if b[i,j] = 7. then LKR-nyomtat(b,X,i 1,j) 8. else LKR-nyomtat(b,X,i,j 1)