This shows you the differences between two versions of the page.
sda-ab:cursuri:12 [2021/03/10 23:16] david.broscoteanu |
sda-ab:cursuri:12 [2021/03/10 23:54] (current) david.broscoteanu [2.1 Prezentare generală] |
||
---|---|---|---|
Line 2: | Line 2: | ||
\\ | \\ | ||
=====1 Obiectivele laboratorului===== | =====1 Obiectivele laboratorului===== | ||
- | *Înțelegerea noțiunilor de bază legate de programarea dinamică | + | * Înțelegerea noțiunilor de bază legate de programarea dinamică |
- | *Însușirea abilităților de implementare a algoritmilor bazați pe programarea dinamică | + | * Însușirea abilităților de implementare a algoritmilor bazați pe programarea dinamică |
- | *Înțelegerea aplicabilității practice a programării dinamice în: | + | * Înțelegerea aplicabilității practice a programării dinamice în: |
- | *Genetică (sequence alignment) | + | * Genetică (sequence alignment) |
- | *Teoria grafurilor (algoritmul Floyd-Warshall) | + | * //Teoria grafurilor (algoritmul Floyd-Warshall)// |
- | *Limbaje formale și automate (algoritmul Cocke-Younger-Kasami,care analizează dacă și în ce fel un șir poate fi generat de o gramatică independentă de context) | + | * Limbaje formale și automate (algoritmul Cocke-Younger-Kasami,care analizează dacă și în ce fel un șir poate fi generat de o gramatică independentă de context) |
- | *Implementarea bazelor de date (algoritmul Selinger pentru optimizarea interogării relaționale) | + | * Implementarea bazelor de date (algoritmul Selinger pentru optimizarea interogării relaționale) |
\\ | \\ | ||
Line 15: | Line 15: | ||
Programarea dinamică presupune rezolvarea unei probleme prin descompunea ei în subprobleme și rezolvarea acestora. Spre deosebire de divide et impera, subprogramele nu sunt disjuncte, ci se suprapun.\\ | Programarea dinamică presupune rezolvarea unei probleme prin descompunea ei în subprobleme și rezolvarea acestora. Spre deosebire de divide et impera, subprogramele nu sunt disjuncte, ci se suprapun.\\ | ||
\\ | \\ | ||
- | Pentru a evita recalcularea porțiunilor care se suprapun, rezolvarea se face pornind de la cele mai mici subprograme și folosindu-ne de rezultatul acestora calculăm subproblema imediat mai mare. Cele mai mici subprobleme sunt numite subprobleme unitare, acestea putând fi rezolvate într-o complexitate constantă, ex:cea mai mare secvență dintr-o mulțime de un singur element. | + | Pentru a evita recalcularea porțiunilor care se suprapun, rezolvarea se face pornind de la cele mai mici subprograme și folosindu-ne de rezultatul acestora calculăm subproblema imediat mai mare. Cele mai mici subprobleme sunt numite **subprobleme unitare**, acestea putând fi rezolvate într-o **complexitate constantă**, //ex:cea mai mare secvență dintr-o mulțime de un singur element//. |
Line 29: | Line 29: | ||
====2.3 Probleme tip rezolvate cu acest algoritm==== | ====2.3 Probleme tip rezolvate cu acest algoritm==== | ||
===2.3.1 Problema rucsacului=== | ===2.3.1 Problema rucsacului=== | ||
- | Soluția se construiește prin programare dinamică, D[i][j]=cel mai bun cost obținut pentru primele i obiecte, având greutatea maxim j.\\ | + | Soluția se construiește prin programare dinamică, **D[i][j]=cel mai bun cost obținut pentru primele i obiecte, având greutatea maxim j**.\\ |
- | Relația de recurență este următoarea: D[i][j]=maxim(D[i-1][j],D[i-1][j-G[i]]+C[i]),unde G[i]=greutatea obiectului i, iar C[i]=costul obiectului.\\ | + | Relația de recurență este următoarea: **D[i][j]=maxim(D[i-1][j],D[i-1][j-G[i]]+C[i])**,unde **G[i]=greutatea obiectului i**, iar **C[i]=costul obiectului**.\\ |
- | Ideea este următoarea: La soluția curentă ori nu adăugăm deloc obiectul i, și rămânem la costul pentru i-1 obiecte, ori adăugăm obiectul i, caz în care adăugăm costul lui la costul obținut pentru primele i-1 obiecte și greutate j-G[i].\\ | + | Ideea este următoarea: //La soluția curentă ori nu adăugăm deloc obiectul i, și rămânem la costul pentru i-1 obiecte, ori adăugăm obiectul i, caz în care adăugăm costul lui la costul obținut pentru primele i-1 obiecte și greutate j-G[i]//.\\ |
===2.3.2 Determinarea celui mai lung subșir crescător=== | ===2.3.2 Determinarea celui mai lung subșir crescător=== | ||
Line 51: | Line 51: | ||
Fie C<sub>n,k</sub> notat şi C(n, k) = combinări de n luate câte k. | Fie C<sub>n,k</sub> notat şi C(n, k) = combinări de n luate câte k. | ||
\\ | \\ | ||
- | Atunci C(n, k) = n! / ( k! (n-k)! ). | + | Atunci **C(n, k) = n! / ( k! (n-k)! )**. |
<note important> | <note important> | ||
Se poate deduce o formulă ce necesită o înmulţire şi o împărţire pentru calcularea unei combinări, deşi există o recurenţă mai bună. | Se poate deduce o formulă ce necesită o înmulţire şi o împărţire pentru calcularea unei combinări, deşi există o recurenţă mai bună. | ||
- | * C(n+1, k) = (n+1)! / (k! (n+1-k)! ) = ( (n+1) / (n+1-k) ) C(n, k); | + | * **C(n+1, k) = (n+1)! / (k! (n+1-k)! ) = ( (n+1) / (n+1-k) ) C(n, k)**; |
</note> | </note> | ||
- | Totodată, dacă definim polinoamele P(n) := (X + 1)<sup>n</sup> , atunci se pot rescrie P(n) = ∏ (C<sub>n,k</sub> X<sup>k</sup>), unde k = 0,1,2,...,n. | + | Totodată, dacă definim polinoamele P(n) := (X + 1)<sup>n</sup> , atunci se pot rescrie **P(n) = ∏ (C<sub>n,k</sub> X<sup>k</sup>)**, unde //k = 0,1,2,...,n//. |
\\ | \\ | ||
\\ | \\ | ||
Line 69: | Line 69: | ||
//coef(P, k) = coef(X P, k+1)//, pentru orice polinom P şi pentru orice număr natural k. | //coef(P, k) = coef(X P, k+1)//, pentru orice polinom P şi pentru orice număr natural k. | ||
- | Putem deduce o legătură între coeficienţii polinoamelor de tipul P(n) dacă scriem P(n + 1) = (X + 1) P(n) = X P(n) + P(n). | + | Putem deduce o legătură între coeficienţii polinoamelor de tipul P(n) dacă scriem **P(n + 1) = (X + 1) P(n) = X P(n) + P(n)**. |
<note tip> | <note tip> | ||
Line 75: | Line 75: | ||
* coef(**P(n + 1), k**) = coef( X P(n), k) + coef(P(n), k) = **coef(P(n), k-1) + coef(P(n), k)**, pentru orice număr natural (k-1). | * coef(**P(n + 1), k**) = coef( X P(n), k) + coef(P(n), k) = **coef(P(n), k-1) + coef(P(n), k)**, pentru orice număr natural (k-1). | ||
- | Dar coef(P(n), k) = C(n, k), deci am obţinut o recurenţă ce foloseşte doar o adunare. | + | Dar **coef(P(n), k) = C(n, k)**, deci am obţinut o recurenţă ce foloseşte doar o adunare. |
</note> | </note> | ||
==== Exerciții ==== | ==== Exerciții ==== | ||
- | - Construiți o funcție care calculează f(n), unde f = șirul lui Fibonacci; | + | - Construiți o funcție care calculează //f(n)//, unde **f = șirul lui Fibonacci**; |
- | - Construiți o funcție care calculează f(n, k), unde f = combinări de n luate câte k; | + | - Construiți o funcție care calculează //f(n, k)//, unde **f = combinări de n luate câte k**; |
- | - implementați problema rucsacului; | + | - implementați **problema rucsacului**; |
- | - Construiți o funcție care indică ordinea operațiilor la înmulțirea a N matrici pentru a minimiza numărul de înmulțiri între 2 numere; | + | - Construiți o funcție care indică ordinea operațiilor la //înmulțirea a N matrici pentru a minimiza numărul de înmulțiri între 2 numere//; |
- | - construiți o funcție care calculează f(n) = 5<sup>n</sup> % k, unde k este o valoare fixată de la începutul programului; | + | - construiți o funcție care calculează //f(n) = 5<sup>n</sup> % k//, unde k este o valoare fixată de la începutul programului; |
- | - Se dă un vector cu N elemente (v = [v1 v2 ... vn]) ce poate fi secționat în piese după următoarele reguli: a) inițial, tot vectorul reprezintă o piesă; b) o piesă poate reprezenta doar o bucată continuă (nu sare peste vreun element) din vectorul inițial; c) secționarea unei piese duce la înlocuirea piesei respective cu 2 piese mai mici, fără a se pierde niciun element din vector; d) valoarea unei piese este val = (lungimea piesei) x (suma elementelor din piesă). Găsiți secțiunile ce maximizează suma valorilor pieselor. | + | - Se dă un vector cu N elemente //(v = [v1 v2 ... vn])// ce poate fi secționat în piese după următoarele reguli: |
- | + | - inițial, tot vectorul reprezintă o piesă; | |
- | ===== 3. Exerciţii de laborator (Linux) ===== | + | - o piesă poate reprezenta doar o bucată continuă (nu sare peste vreun element) din vectorul inițial; |
- | Pentru acest laborator puteți descărca scheletul de cod de [[http://elf.cs.pub.ro/sda-ab/wiki/_media/laboratoare/lab11_programare_dinamica-skel.zip|aici]]. Descărcați arhiva și dezarhivați-o. | + | - secționarea unei piese duce la înlocuirea piesei respective cu 2 piese mai mici, fără a se pierde niciun element din vector; |
- | + | - valoarea unei piese este val = (lungimea piesei) x (suma elementelor din piesă). Găsiți secțiunile ce maximizează suma valorilor pieselor. | |
- | === Linux=== | + | |
- | Puteti folosi utilitarul ''%%wget%%'' pentru descarcare si utilitarul ''%%unzip%%'' pentru dezarhivare. | + | |
- | + | ||
- | * ''%%wget http://elf.cs.pub.ro/sda-ab/wiki/_media/laboratoare/lab11_programare_dinamica-skel.zip%%'' | + | |
- | * ''%%unzip lab11_programare_dinamica-skel.zip%%'' | + | |
- | + | ||
- | Pentru compilare folositi comanda ''%%make%%''. | + | |