|

Metoda Programării Dinamice în Programare 4


1. Obiectivele lecției:

  • Să înțeleagă conceptul metodei Programării Dinamice.
  • Să învețe cum să rezolve probleme complexe folosind subprobleme suprapuse.
  • Să implementeze exemple practice care folosesc această metodă.

2. Ce este Programarea Dinamică?

  1. Definiție:
    Programarea Dinamică (Dynamic Programming – DP) este o metodă de optimizare care rezolvă probleme complexe prin împărțirea acestora în subprobleme mai mici și memorarea soluțiilor intermediare pentru a evita recalcularea lor.
  2. Cerințe pentru aplicarea metodei:
    • Subprobleme suprapuse: Problemele mai mari pot fi împărțite în subprobleme care se repetă.
    • Substructură optimă: Soluția optimă a unei probleme poate fi construită din soluțiile optime ale subproblemelor.
  3. Tehnici de implementare:
    • Top-Down (Memoization): Soluția este calculată recursiv, iar rezultatele intermediare sunt memorate.
    • Bottom-Up (Tabulation): Se construiește soluția într-un mod iterativ, pornind de la cele mai mici subprobleme.

3. Avantaje și dezavantaje

AvantajeDezavantaje
Reduce recalculările prin memorarea soluțiilor.Necesită mai multă memorie pentru stocarea intermediară.
Garantează o soluție optimă, dacă există.Poate fi dificil de implementat pentru probleme complexe.
Eficient pentru probleme care au subprobleme repetate.Necesită identificarea clară a subproblemelor.

4. Probleme rezolvate prin Programare Dinamică

  1. Fibonacci.
  2. Problema rucsacului (Knapsack problem).
  3. Cel mai lung subșir comun (Longest Common Subsequence – LCS).
  4. Număr de drumuri într-o matrice.
  5. Problema sumei parțiale.

5. Etapele metodei

  1. Formularea problemei:
    Identificați cum poate fi împărțită problema principală în subprobleme mai mici.
  2. Definirea stării:
    Definește starea problemei ca o relație recurentă (dp[i]dp[i]dp[i], dp[i][j]dp[i][j]dp[i][j], etc.).
  3. Relația de recurență:
    Scrieți relația care definește cum se construiește soluția din subproblemele anterioare.
  4. Cazul de bază:
    Definește condițiile inițiale pentru algoritm.
  5. Implementarea algoritmului:
    Implementați metoda folosind tehnici top-down sau bottom-up.

6. Exemple practice


Exemplu 1: Numerele Fibonacci

  1. Problema:
    Calculați al nnn-lea număr din șirul Fibonacci.
  2. Relația de recurență:

F(n)=F(n−1)+F(n−2)F(n) = F(n-1) + F(n-2)F(n)=F(n−1)+F(n−2)

cu F(0)=0F(0) = 0F(0)=0 și F(1)=1F(1) = 1F(1)=1.

  1. Implementare Bottom-Up:

#include <iostream>

using namespace std;

int fibonacci(int n) {

    if (n <= 1) return n;

    int dp[n + 1];

    dp[0] = 0;

    dp[1] = 1;

    for (int i = 2; i <= n; i++) {

        dp[i] = dp[i – 1] + dp[i – 2];

    }

    return dp[n];

}

int main() {

    int n = 10;

    cout << „Fibonacci(” << n << „) = ” << fibonacci(n) << endl;

    return 0;

}


Exemplu 2: Problema rucsacului (Knapsack Problem)

  1. Problema:
    Avem un rucsac cu o capacitate WWW și nnn obiecte, fiecare cu o greutate w[i]w[i]w[i] și o valoare v[i]v[i]v[i]. Găsiți valoarea maximă care poate fi transportată.
  2. Relația de recurență:

dp[i][w]=max⁡(dp[i−1][w],v[i]+dp[i−1][w−w[i]])dp[i][w] = \max(dp[i-1][w], v[i] + dp[i-1][w-w[i]])dp[i][w]=max(dp[i−1][w],v[i]+dp[i−1][w−w[i]])

  1. Implementare Bottom-Up:

#include <iostream>

#include <vector>

using namespace std;

int knapsack(int W, vector<int>& greutati, vector<int>& valori, int n) {

    vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));

    for (int i = 1; i <= n; i++) {

        for (int w = 0; w <= W; w++) {

            if (greutati[i – 1] <= w) {

                dp[i][w] = max(dp[i – 1][w], valori[i – 1] + dp[i – 1][w – greutati[i – 1]]);

            } else {

                dp[i][w] = dp[i – 1][w];

            }

        }

    }

    return dp[n][W];

}

int main() {

    vector<int> greutati = {1, 2, 3};

    vector<int> valori = {10, 15, 40};

    int W = 6;

    cout << „Valoarea maximă: ” << knapsack(W, greutati, valori, greutati.size()) << endl;

    return 0;

}


Exemplu 3: Cel mai lung subșir comun (Longest Common Subsequence – LCS)

  1. Problema:
    Găsiți lungimea celui mai lung subșir comun între două șiruri.
  2. Relația de recurență:

dp[i][j]={dp[i−1][j−1]+1,daca˘ s1[i]==s2[j]max⁡(dp[i−1][j],dp[i][j−1]),altfeldp[i][j] = \begin{cases} dp[i-1][j-1] + 1, & \text{dacă } s1[i] == s2[j] \\ \max(dp[i-1][j], dp[i][j-1]), & \text{altfel} \end{cases}dp[i][j]={dp[i−1][j−1]+1,max(dp[i−1][j],dp[i][j−1]),​daca˘ s1[i]==s2[j]altfel​

  1. Implementare Bottom-Up:

#include <iostream>

#include <vector>

using namespace std;

int lcs(string s1, string s2) {

    int n = s1.size(), m = s2.size();

    vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));

    for (int i = 1; i <= n; i++) {

        for (int j = 1; j <= m; j++) {

            if (s1[i – 1] == s2[j – 1]) {

                dp[i][j] = dp[i – 1][j – 1] + 1;

            } else {

                dp[i][j] = max(dp[i – 1][j], dp[i][j – 1]);

            }

        }

    }

    return dp[n][m];

}

int main() {

    string s1 = „ABCBDAB”;

    string s2 = „BDCAB”;

    cout << „Lungimea celui mai lung subșir comun: ” << lcs(s1, s2) << endl;

    return 0;

}


7. Activități practice pentru elevi

  1. Implementați un algoritm DP pentru a calcula numărul de drumuri posibile într-o matrice n×mn \times mn×m, pornind din colțul stânga-sus și terminând în colțul dreapta-jos.
  2. Scrieți un program care determină suma maximă a unui drum dintr-o matrice triunghiulară (Triangle Path Sum).
  3. Realizați un program DP care determină numărul de moduri de a face o sumă SSS utilizând un set de monede.

8. Scheme logice

  1. Flux Programare Dinamică:
    • Start -> Definire stare -> Relație de recurență -> Construire soluție (Bottom-Up) -> Stop.
  2. Vizualizare LCS:
    • Construirea unei matrice dp[i][j]dp[i][j]dp[i][j] pentru fiecare pereche de caractere.

9. Concluzie

  • Programarea Dinamică este o metodă extrem de eficientă pentru probleme complexe cu subprobleme suprapuse.
  • Memorarea soluțiilor intermediare reduce semnificativ timpul de execuție.
  • Practica ajută la identificarea problemelor care pot fi rezolvate eficient prin această metodă.

Similar Posts

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *