Platformă de e-learning și curriculă e-content pentru învățământul superior tehnic Proiectarea Algoritmilor 4. Scheme de algoritmi Programare dinamica
Bibliografie Cormen Introducere în Algoritmi cap. 17 Giumale Introducere in Analiza Algoritmilor cap 4.4,4.5 http://www.cs.umass.edu/~barring/cs611/lecture/4.pdf http://thor.info.uaic.ro/~dlucanu/cursuri/tpaa/resurse/curs6.pps http://www.math.fau.edu/locke/greedy.htm http://en.wikipedia.org/wiki/greedoid http://activities.tjhsst.edu/sct/lectures/greedy0607.pdf http://www.cse.ust.hk/~dekai/271/notes/l12/l12.pdf
Programare dinamică Programare dinamică Descriere generală Algoritm generic Caracteristici Exemplificare: Înmulțirea matricilor Exemplificare: Arbori optimi la căutare (AOC) Definiții Construcția AOC
Programare dinamica Descriere generală Soluții optime construite iterativ asamblând soluții optime ale unor probleme similare de dimensiuni mai mici. Algoritmi clasici Algoritmul Floyd-Warshall care determină drumurile de cost minim dintre toate perechile de noduri ale unui graf. AOC Înmulţirea unui şir de matrici Numere catalane Viterbi
Algoritm generic Programare dinamică (crit_optim, problema) // fie problema 0 problema 1 problema n astfel încât // problema n = problema; problema i mai simpla decât problema i+1 1. Sol = soluții_inițiale(crit_optim, problema 0 ); 2. Pentru i = 1 n Repetă // construcție soluții pentru problema i // folosind soluțiile problemelor precedente 3. Sol i = calcul_soluții(sol, Crit_optim, Problema i ); // determin soluția problemei i 4. Sol = Sol U Sol i ; // noua soluție se adaugă pentru a fi refolosită pe viitor 5. s = soluție_pentru_problema n (Sol); // selecție / construcție soluție finala 6. Întoarce s;
Caracteristici O soluție optimă a unei probleme conține soluții optime ale subproblemelor. Decompozabilitatea recursivă a problemei P in subprobleme similare P = P n, P n-1, P 0 care acceptă soluții din ce in ce mai simple. Suprapunerea problemelor (soluția unei probleme P i participă in procesul de construcție a soluțiilor mai multor probleme P k de talie mai mare k > i) memoizare (se foloseşte un tablou pentru salvarea soluţiilor subproblemelor pentru a nu le recalcula) In general se folosește o abordare bottom-up, de la subprobleme la probleme.
Diferențe Greedy programare dinamică Programare lacomă Programare dinamică Sunt menținute doar soluțiile parțiale curente din care evoluează soluțiile parțiale următoare Soluțiile parțiale anterioare sunt eliminate Se păstrează toate soluțiile parțiale La construcția unei soluții noi poate contribui orice altă soluție parțială generată anterior Se poate obține o soluție neoptimă. (trebuie demonstrat că se poate aplica) Se obține soluția optimă.
Diferenţe divide et impera programare dinamică Divide et impera abordare top-down problema este descompusă în subprobleme care sunt rezolvate independent putem rezolva aceeaşi problemă de mai multe ori (dezavantaj potenţial foarte mare) Programare dinamică abordare bottom-up - se porneşte de la sub-soluţii elementare şi se combină sub-soluţiile mai simple în sub-soluţii mai complicate, pe baza criteriului de optim se evită calculul repetat al aceleiaşi subprobleme prin memorarea rezultatelor intermediare
Exemplu: Parantezarea matricilor (Chain Matrix Multiplication) Se dă o şir de matrice: A 1, A 2,..., A n. Care este numărul minim de înmulţiri de scalari pentru a calcula produsul: A 1 x A 2 x... x A n? Să se determine una dintre parantezările care minimizează numărul de înmulţiri de scalari.
Înmulţirea matricilor A(p, q) x B (q, r) => pqr înmulţiri de scalari. Dar înmulţirea matricilor este asociativă (deşi nu este comutativă). A(p, q) x B (q, r) x C(r, s) (AB)C => pqr + prs înmulţiri A(BC) => qrs + pqs înmulţiri Ex: p = 5, q = 4, r = 6, s = 2 (AB)C => 180 înmulţiri A(BC) => 88 înmulţiri Concluzie: Parantezarea este foarte importantă!
Soluţia banală Matrici: A 1, A 2,..., A n. Vector de dimensiuni: p 0, p 1, p 2,..., p n. A i (p i-1, p i ) A 1 (p 0, p 1 ), A 2 (p 1, p 2 ), Dacă folosim căutare exhaustivă şi vrem să construim toate parantezările posibile pentru a determina minimul: Ω(4 n / n 3/2 ). Vrem o soluţie polinomială folosind P.D.
Descompunere în subprobleme Încercăm să definim subprobleme identice cu problema originală, dar de dimensiune mai mică. 1 i j n: Notăm A i, j = A i x x A j. A i,j are p i-1 linii si p j coloane: A i,j (p i-1, p j ) m[i, j] = numărul optim de înmulţiri pentru a rezolva subproblema A i,j s[i, j] = poziţia primei paranteze pentru subproblema A i,j Care e parantezarea optimă pentru A i, j? Problema iniţială: A 1,n
Combinarea subproblemelor Pentru a rezolva A i,j trebuie găsit acel indice i k < j care asigură parantezarea optimă: A i, j = (A i x x A k ) x (A k+1 x x A j ) A i, j = A i, k x A k+1, j
Alegerea optimală Căutăm optimul dintre toate variantele posibile de alegere (i k < j) Pentru aceasta, trebuie însă ca şi subproblemele folosite să aibă soluţie optimală (adică A i, k şi A k+1, j )
Substructura optimală Dacă ştim că alegerea optimală a soluţiei pentru problema A i, j implică folosirea subproblemelor (A i, k şi A k+1, j ) şi soluţia pentru A i, j este optimală, atunci şi soluţiile subproblemelor A i, k şi A k+1, j trebuie să fie optimale! Demonstraţie: Folosind metoda cut-and-paste (metodă standard de demonstrare a substructurii optimale pentru problemele de programare dinamică). Observație: Nu toate problemele de optim posedă această proprietate! Ex: drumul maxim dintr-un graf orientat.
Definirea recursivă Folosind descompunerea in subprobleme, combinarea subproblemelor, alegerea optimală şi substructura optimală putem să rezolvăm problema prin programare dinamică. Următorul pas este să definim recursiv soluţia unei subprobleme. Vrem să găsim o formulă recursivă pentru m[i, j] şi s[i, j].
Definirea recursivă (II) Cazurile de bază sunt m[i, i] Noi vrem să calculăm m[1, n] Cum alegem s[i, j]? Bottom-up de la cele mai mici subprobleme la cea iniţială
Rezolvare bottom-up
Rezolvare - iniţializare
Rezolvare pas intermediar
Rezolvare final
Pseudocod
Complexitate Spaţială: Θ(n 2 ) Pentru memorarea soluţiilor subproblemelor Temporală: O(n 3 ) Ns: Număr total de subprobleme: O(n 2 ) Na: Număr total de alegeri la fiecare pas: O(n) Complexitatea este de obicei egala cu Ns x Na
Arbori optimi la căutare Def 2.1: Fie K o mulțime de chei. Un arbore binar cu cheile K este un graf orientat si aciclic A = (V,E) a.i.: Fiecare nod u V conține o singură cheie k(u) K iar cheile din noduri sunt distincte. Există un nod unic r V a.i. i-grad(r) = 0 si u r, i-grad(u) = 1. u V, e-grad(u) 2; S(u) / D(u) = succesorul stânga / dreapta. Def 2.2: Fie K o mulțime de chei peste care exista o relație de ordine. Un arbore binar de căutare satisface: u,v,w V avem (v S(u) => cheie(v) cheie(u)) (w D(u) => cheie(u) cheie(w))
Căutare Caută(elem, Arb) Dacă Arb = null Întoarce null Dacă elem = Arb.val // valoarea din nodul crt. Întoarce Arb Dacă elem Arb.val Întoarce Caută(elem, Arb.st) Întoarce Caută(elem, Arb.dr) Complexitate: Θ(logn)
Inserţie în arbore de căutare Inserare(elem, Arb) Dacă Arb = vid // adaug cheia in arbore nod_nou(elem, null, null) Dacă elem = Arb.val // valoarea există deja Întoarce Arb Dacă elem Arb.val Întoarce Inserare(elem, Arb.st) // adaugă in stânga Întoarce Inserare(elem, Arb.dr) // sau in dreapta Complexitate: Θ(logn) nod Stânga nod Dreapta
Exemplu de arbori de căutare Cu aceleaşi chei se pot construi arbori distincţi 8 A 23 15 32 28 41 A1 23 15 32 8 19 28 41 8 A2 23 28 32 41 19 15 19
Exemplu (I) presupunem că elementele din A1 şi A2 au probabilităţi de căutare egale: numărul mediu de comparaţii pentru A1 va fi: (1 + 2 + 2 + 3 + 3 + 3 + 3) / 7 = 2.42 numărul mediu de comparaţii pentru A2 va fi: (1 + 2 + 2 + 3 + 3 + 4 + 5) / 7 = 2.85 A1 A2 23 15 32 8 19 28 41 8 23 15 28 19 32 41
Exemplu (II) presupunem că elementele au următoarele probabilităţi: 8: 0.2; 15: 0.01; 19: 0.1; 23: 0.02; 28: 0.25; 32: 0.2; 41: 0.22; numărul mediu de comparaţii pentru A1: 0.02*1+0.01*2+0.2*2+0.2*3+0.1*4+0.25*3+0.22*3=2.85 numărul mediu de comparaţii pentru A2: 0.25*1+0.02*2+0.22*2+0.2*3+0.2*3+0.01*4+0.1*5=2.47 A1 A2 23 15 32 8 19 28 41 8 23 15 28 19 32 41
Probleme Costul căutării depinde de frecvenţa cu care este căutat fiecare termen. Ne dorim ca termenii cei mai des căutaţi să fie cât mai aproape de vârful arborelui pentru a micşora numărul de apeluri recursive. Dacă arborele este construit prin sosirea aleatorie a cheilor putem ajunge la o simplă listă cu n elemente
Definiţie AOC Definiție: Fie A un arbore binar de căutare cu chei intro mulțime K, fie {x 1, x 2, x n } cheile conținute in A, iar {y 0, y 1, y n } chei reprezentante ale cheilor din K ce nu sunt in A astfel încât: yi 1 xi yi, i 1, n. Fie p i, i = 1,n probabilitatea de a căuta cheia x i si q j, j = 0,n probabilitatea de a căuta o cheie reprezentata de y j. n n Vom avea relația: p i q j 1. Se numește arbore i1 j0 de căutare probabilistică, un arbore cu costul: n Cost ( A) ( nivel( x, A) 1) * p i1 i nivel( y Definiție: Un arbore de căutare probabilistică având cost minim este un arbore optim la căutare (AOC). i n j0 j, A) * q j
Algoritm AOC naiv Generarea permutărilor x 1,... x n. Construcţia arborilor de căutare corespunzători. Calcularea costului pentru fiecare arbore. Alegerea arborelui de cost minim. Complexitate: Θ(n!) (deoarece sunt n! permutări). căutăm altă variantă!!!
Construcţia AOC Notaţii A i,j desemnează un AOC cu cheile {x i+1, x i+2, x j } in noduri si cu cheile {y i, y i+1, y j } in frunzele fictive. C i,j = Cost (A i,j ). Cost( A ) ij j ki1 ( nivel ( x k, A ) 1)* ij p k j ki nivel ( y k, A )* q ij k R i,j este indicele α al cheii x α din rădăcina arborelui A i,j. wi, j j ki1 p k j ki q k Observație: A 0,n este chiar arborele A, C 0,n = Cost (A) iar w 0,n = 1.
Construcţia AOC - Demonstraţie Lemă: Pentru orice 0 i j n există relaţiile: C i,j = 0, daca i = j; (arbore vid) C i, j min{ Ci, 1 C, j} wi, j i j A i, α-1 = S(A i, j ) A i, j x α A α, j = D(A i, j ) Demonstrație: Cost( A ) ij ki1 C i, j Ci, 1 C, j wi, j j ( nivel ( x k, A ) 1)* ij p k x i+1,...x α-1 y i,...y α-1 j ki nivel ( y k, A )* q ij x α+1,...x j y α+1,...y j k C i,j depinde de indicele α al nodului rădăcină. dacă C i,α-1 şi C α,j sunt minime (costurile unor AOC) C i,j este minim.
Construcţia AOC 1. In etapa d, d = 1, 2, n se calculează costurile si indicele cheilor din rădăcina arborilor AOC A i, i+d, i = 0, n-d cu d noduri si d + 1 frunze fictive. Arborele A i, i+d conține in noduri cheile {x i+1, x i+2, x i+d }, iar in frunzele fictive sunt cheile {y i, y i+1, y i+d }. Calculul este efectuat pe baza rezultatelor obținute in etapele anterioare. Conform lemei avem C i, id min { Ci, 1 C, id} wi, id i id Rădăcina A i, i+d are indicele R i, j = α care minimizează C i, i+d. 2. Pentru d = n, C 0, n corespunde arborelui AOC A 0, n cu cheile {x 1, x 2, x n } in noduri si cheile {y 0, y 1, y n } in frunzele fictive.
Algoritm AOC AOC(x, p, q, n) Pentru i = 0 n {C i, i = 0, R i, i = 0, w i,i = q i } // inițializare costuri AOC vid A i, i Pentru d = 1 n Pentru i = 0 n-d // calcul indice rădăcina si cost pentru A i, i+d j = i + d, C i, j =, w i, j = w i, j-1 + p j + q j Pentru α = i + 1 j // ciclul critic operații intensive Dacă (C i, α-1 + C α, j < C i, j ) // cost mai mic? C i, j = C i, j + w i, j // update { C i, j = C i, α-1 + C α, j ; R i, j = α} // update Întoarce gen_aoc(c, R, x, 0, n) // construcție efectiva arbore A 0, n // cunoscând indicii Complexitate???
Exemplu constructie AOC (I) 8: 0.2; 15: 0.01; 19: 0.1; 23: 0.02; 28: 0.25; (58%) [0:8): 0.02; (8:15): 0.07; (15:19): 0.08; (19:23): 0.05; (23:28): 0.05; (28, ): 0.15 (42%) C 01 =p 1 +q 0 +q 1 =0.29 C 12 =p 2 +q 1 +q 2 =0.16 C 23 =p 3 +q 2 +q 3 =0.25 C 34 =p 4 +q 3 +q 4 =0.02+0.05+0.05=0.12 C 45 =p 5 +q 4 +q 5 =0.25+0.05+0.15=0.45 w j p j q C min { C C w, i, j k k i id i, 1, id i id ki1 ki i id, }
Exemplu constructie AOC (II) A 01 :0.29 8 A 12 :0.16 15 A 23 :0.25 19 A 34 :0.12 23 A 45 :0.45 28 <8 8-15 8-15 15-19 15-19 19-23 19-23 23-28 23-28 >28 C 02 = min {(C 00 +C 12 ),(C 01 +C 22 )} + w 02 = min(0.16,0.29) + 0.38 = 0.54 R 02 = 1 (α=1) C 13 = min{c 23,C 12 } + w 13 = min(0.25,0.16) + 0.31 = 0.47 R 13 = 3 C 24 = min{c 34,C 23 } + w 24 = min(0.12,0.25) + 0.3 = 0.42 R 24 = 3 C 35 = min{c 45,C 34 } + w 35 = min(0.45,0.12) + 0.52 = 0.64 R 35 = 5 8 A 02 :0.54 A 13 :0.47 19 A 24 :0.42 19 A 35 :0.64 28 <8 15 15 19-23 15-19 23 23-28 23 8-15 15-19 8-15 15-19 19-23 23-28 19-23 23-28 w j p j q C, min { C C } w, i id i, j k k i id i, 1, id i i ki1 ki d
Exemplu constructie AOC (III) C 03 = min(c 00 +C 13, C 01 +C 23, C 02 +C 33 ) + w 03 = min (0.47,0.54, 0.54) + w 03 => R 03 =1 C 14 = min(c 11 +C 24,C 12 +C 34,C 13 +C 44 ) + w 14 = min(0.42,0.28, 0.47) + w 14 => R 14 = 3 C 25 = min(c 22 +C 35,C 23 +C 34, C 24 +C 55 ) + w 25 = min(0.64, 0.37, 0.42) + w 25 => R 25 = 4 8 <8 19 15 19-23 8-15 15-19 19 15 23 8-15 15-1919-23 23-28 19 15-19 19-23 23 28 23-28 >28 w j p j q C, min { C C } w, i id i, j k k i id i, 1, id i id ki1 ki
AOC Corectitudine (I) Teoremă: Algoritmul AOC construiește un arbore AOC A cu cheile x = {x 1, x 2, x n } conform probabilităților de căutare p i, i = 1,n si q j, j = 0,n. Demonstrație: prin inducție după etapa de calcul al costurilor arborilor cu d noduri. Caz de baza: d = 0. Costurile C i, i ale arborilor vizi A i, i, i = 0, n sunt 0, așa cum sunt inițializate de algoritm. Pas de inducție: d 1. Ip. ind.: pentru orice d < d, algoritmul AOC calculează costurile C i, i+d si indicii R i, i+d, ai rădăcinilor unor AOC A i, i+d, i = 0, n-d cu cheile {x i+1, x i+2, x i+d }. Trebuie sa arătam ca valorile C i, i+d si R i, i+d corespund unor AOC A i, i+d, i = 0, n-d cu cheile {x i+1, x i+2, x i+d }.
AOC Corectitudine (II) Pentru d si i fixate, algoritmul calculează: C i, id min { Ci, 1 C, id} wi, id i id unde costurile C i, α-1 si C α, i+d corespund unor arbori cu un număr de noduri d = α 1 i in cazul C i, α-1 si d = i + d α in cazul C α, i+d. 0 d d 1 aceste valori au fost deja calculate in etapele d < d si conform ipotezei inductive sunt costuri si indici ai rădăcinilor unor AOC. Conform Lemei anterioare, C i, j este costul unui AOC. Conform algoritmului rădăcina acestui arbore are indicele r = R i, j, iar cheile sunt {x i+1, x i+2, x r-1 } {x r } {x r+1, x r+2, x j } = {x i+1, x i+2, x j } Pentru d = n, costul C 0, n corespunde unui AOC A 0, n cu cheile x si cu rădăcina de indice R 0, n.
AOC Concluzii Câte subprobleme sunt folosite în soluţia optimală intr-un anumit pas? AOC: 2 subprobleme Câte variante de ales avem de făcut pentru determinarea alegerii optimale intr-un anumit pas? AOC: j i + 1 candidaţi pentru rădăcină Informal, complexitatea = Ns * Na (Ns = număr subprobleme; Na = număr alegeri) Complexitate AOC: O(n 2 ) * O(n) = O(n 3 ) Optimizare Knuth: O(n 2 )