Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pa:laboratoare:laborator-04 [2021/03/15 08:49]
miruna_elena.banu [Gardurile lui Gigel]
pa:laboratoare:laborator-04 [2024/04/16 17:38] (current)
radu.nichita
Line 1: Line 1:
-====== Laborator 4: Programare Dinamică (continuare) ====== +====== Laborator 04: Programare Dinamică (2/2) ======
-Responsabili:​ +
-  * [[neatudarius@gmail.com|Darius-Florentin Neațu (2017-2021)]] +
-  * [[radunichita99@gmail.com | Radu Nichita (2021)]] +
-  * [[cristianolaru99@gmail.com | Cristian Olaru (2021)]] +
-  * [[mirunaelena.banu@gmail.com ​ | Miruna-Elena Banu (2021)]] +
-  * [[maraioana9967@gmail.com | Mara-Ioana Nicolae (2021)]] +
-  * [[stefanpopa2209@gmail.com | Ștefan Popa (2018-2020)]] +
- +
-Autori: +
-  * [[neatudarius@gmail.com|Darius-Fforentin Neațu (2018)]] +
-  * [[visanr95@gmail.com|Radu Vișan (2018)]] +
-  * [[cristb@gmail.com|Cristian Banu (2018)]] +
-  * [[razvan.ch95@gmail.com|Răzvan Chițu (2018)]] +
  
 ===== Obiective laborator ===== ===== Obiective laborator =====
Line 102: Line 88:
        * explicație:​ $X =(BC)$ generează $3 * 4 * 5 = 60$ înmulțiri,​ $(AX)$ generează $2 * 3 * 5 = 30$ de înmulțiri        * explicație:​ $X =(BC)$ generează $3 * 4 * 5 = 60$ înmulțiri,​ $(AX)$ generează $2 * 3 * 5 = 30$ de înmulțiri
        
-Rezultatul optim se obține pentru ​cea de a treia parantezare:​ $(AB)C$.+Rezultatul optim se obține pentru ​prima parantezare:​ $(AB)C$.
    
 </​spoiler>​ </​spoiler>​
Line 165: Line 151:
 == Numire recurență === == Numire recurență ===
 $dp[i][j]$ = **numărul minim de înmulțiri scalare** cu care se poate obține produsul $M_i * M_{i+1} * ... *{M_j}$ ​ $dp[i][j]$ = **numărul minim de înmulțiri scalare** cu care se poate obține produsul $M_i * M_{i+1} * ... *{M_j}$ ​
 +
 +Răspunsul la problemă este **dp[1][n]** .
  
 == Găsire recurență == == Găsire recurență ==
Line 186: Line 174:
 <spoiler Implementare C++> <spoiler Implementare C++>
 <code cpp> <code cpp>
-// kInf este valoarea maximă - "​infinitul"​ nostru +// INF este valoarea maximă - "​infinitul"​ nostru 
-const unsigned long long kInf = std::​numeric_limits<​unsigned long long>::​max();​+const auto INF = std::​numeric_limits<​unsigned long long>::​max();​
  
 // T = O(n ^ 3)  // T = O(n ^ 3) 
Line 194: Line 182:
     // dp[i][j] = numărul MINIM înmulțiri scalare cu codare, poate fi calculat produsul     // dp[i][j] = numărul MINIM înmulțiri scalare cu codare, poate fi calculat produsul
     //            matriceal M_i * M_i+1 * ... * M_j     //            matriceal M_i * M_i+1 * ... * M_j
-    vector<​vector<​unsigned long long>> ​ dp(n + 1, vector<​unsigned long long> (n + 1, kInf));+    vector<​vector<​unsigned long long>> ​ dp(n + 1, vector<​unsigned long long> (n + 1, INF));
  
     // Cazul de bază 1: nu am ce înmulți ​     // Cazul de bază 1: nu am ce înmulți ​
Line 242: Line 230:
  
 <​note>​ <​note>​
-**ATENȚIE!** La PA, în general, vom folosi convenția $ expresie \ \%  \ kMod $, care va fi detaliată în capitolul următor din acest laborator. ​+**ATENȚIE!** La PA, în general, vom folosi convenția $ expresie \ \%  \ MOD $, care va fi detaliată în capitolul următor din acest laborator. ​
 </​note>​ </​note>​
  
Line 418: Line 406:
     * se poate obține $S = O(1)$ folosind exponențiere pe matrice! ​     * se poate obține $S = O(1)$ folosind exponențiere pe matrice! ​
  
-===== Tehnici folosite ​in DP ===== +===== Tehnici folosite ​în DP ===== 
-De multe ori este nevoie ​sa folosim ​cateva ​tehnici pentru a obtine performanta maxima ​cu recurenta gasita.+De multe orieste nevoie ​să folosim ​câteva ​tehnici pentru a obține performanța maximă ​cu recurența găsită.
  
-In laboratorul ​3 se mentiona ​tehnica de memoizare ​(in prima parte a laboratorului)In acesta ne vom rezuma la cum putem folosi ​cunostintele ​de lucru matricial ​pentru a favoriza implementarea unor anumite tipuri de recurente.+În prima parte a laboratorului ​3 se menționa ​tehnica de memoizare. ​În acestane vom rezuma la cum putem folosi ​cunoștințele ​de lucru matriceal ​pentru a favoriza implementarea unor anumite tipuri de recurențe.
  
-==== Exponentiere ​pe matrice pentru ​recurente ​liniare ==== +==== Exponențiere ​pe matrice pentru ​recurențe ​liniare ==== 
-=== Recurente ​liniare=== +=== Recurențe ​liniare === 
-recurenta liniara in contextul laboratorului de DP este de forma:+recurență liniară, în contextul laboratorului de DPeste de forma:
   * $dp[i] = \sum_{k=1}^{KMAX} c_k * dp[i - k]$   * $dp[i] = \sum_{k=1}^{KMAX} c_k * dp[i - k]$
-    * pentru **KMAX o constanta** +    * pentru **KMAX o constantă** 
-    * de obicei, KMAX este foarte ​mica comparativ cu dimensinea ​n a problemei+    * de obicei, KMAX este foarte ​mică comparativ cu dimensiunea ​n a problemei
     * $c_k$ constante reale (unele pot fi nule)     * $c_k$ constante reale (unele pot fi nule)
  
-O astfel de recurenta ​ar insemna ca pentru a calcula ** costul problemei i **, imbinam ​costurile problemelor $i - 1, i-2, ...., i-k$, fiecare contribuind cu un anumit coeficient $c_{1}, c_{2}, ..., c_{k}$.+O astfel de recurență ​ar însemna că, pentru a calcula **costul problemei i**, îmbinăm ​costurile problemelor $i - 1, i - 2, ...., i - k$, fiecare contribuind cu un anumit coeficient $c_{1}, c_{2}, ..., c_{k}$.
  
-<spoiler Complexitate ​recurente liniara>  +<spoiler Complexitate ​recurențe liniară>  
-Presupunand ca nu mai exista ​alte specificatii ​ale problemei ​si ca avand cele KMAX cazuri de baza (primele KMAX valori ar trebui ​stiute/deduse prin alte reguli), atunci un algoritm poate implementa ​recurenta ​de mai sus folosind 2 cicluri de tip for (for i = 1 : n, for k = 1 : KMAX ...). +Presupunând că nu mai există ​alte specificații ​ale problemei ​și că, având ​cele KMAX cazuri de bază, ​(primele KMAX valori ar trebui ​știute/deduse prin alte reguli), atunci un algoritm poate implementa ​recurența ​de mai sus folosind 2 cicluri de tipfor (for i = 1 : n, for k = 1 : KMAX ...). 
-  * **complexitatea ​temporala** : $ T =O(n * KMAX) = O(n) $ +  * **complexitatea ​temporală** : $T = O(n * KMAX) = O(n)$ 
-    * reamintim ​ca acea valoarea ​KMAX este o constanta ​foarte ​mica in compartie ​cu n (ex. KMAX < 100) +    * reamintim ​că acea valoare ​KMAX este o constantă ​foarte ​mică în comparație ​cu n (ex. KMAX < 100) 
-  * **complexitatea ​spatiala** : $ S = O(n) $+  * **complexitatea ​spațială** : $S = O(n)$
  
-    * am presupus ​ca avem nevoie ​sa retinem ​doar tabloul dp  ​+    * am presupus ​că avem nevoie ​să reținem ​doar tabloul dp  ​
 </​spoiler>​ </​spoiler>​
  
-=== Exponentiere ​pe matrice === +=== Exponențiere ​pe matrice === 
-Facem urmatoarele notatii:+Facem următoarele notații:
   * $S_i$ = starea la pasul i   * $S_i$ = starea la pasul i
     * $S_i = (dp[i - k + 1], dp[i - k + 2], ..., dp[i - 1], dp[i])$     * $S_i = (dp[i - k + 1], dp[i - k + 2], ..., dp[i - 1], dp[i])$
-  * $S_k$ = starea ​initiala ​(in care cunoaste ​cele k cazuri de baza)+  * $S_k$ = starea ​inițială ​(în care cunoaște ​cele k cazuri de bază)
     * $S_k = (dp[1], dp[2], ..., dp[k-1], dp[k])$     * $S_k = (dp[1], dp[2], ..., dp[k-1], dp[k])$
-  * $C$ = matrice ​ce coeficienti constanti+  * $C$ = matrice ​de coeficienți constanți
     * are dimensiune $KMAX * KMAX$      * are dimensiune $KMAX * KMAX$ 
-    * putem pune constante ​in clar +    * putem pune constante ​în clar 
-    * putem pune constantele $c_k$ care tin de problema ​curenta+    * putem pune constantele $c_k$ care țin de problema ​curentă
  
  
Line 457: Line 445:
 == Algoritm naiv == == Algoritm naiv ==
 Putem formula problema astfel: Putem formula problema astfel:
-  * $S_k$ = este starea ​initiala +  * $S_k$ = este starea ​inițială 
-  * pentru a obtine ​starea ​urmatoareaplicam ​algoritmul ​urmator+  * pentru a obține ​starea ​următoareaplicăm ​algoritmul ​următor
      * $S_i = S_{i-1}C$  ​      * $S_i = S_{i-1}C$  ​
   ​   ​
 == Determinare C == == Determinare C ==
-Pentru a determina elementele matricei C, trebuie ​sa ne uitam la inmultirea matriceala ​de mai sus si sa alegem elementele lui C astfel ​incat prin inmultirealui ​$S_{i-1}$ cu $C$ sa obtinem ​elementele din $S_i$.+Pentru a determina elementele matricei C, trebuie ​să ne uităm ​la înmulțirea matriceală ​de mai sus și să alegem elementele lui C astfel ​încât ​prin înmulțirea lui $S_{i-1}$ cu $C$ să obținem ​elementele din $S_i$.
  
 \begin{gather} \begin{gather}
Line 481: Line 469:
  
  
-<​spoiler ​Explicatie ​determinare C> +<​spoiler ​Explicație ​determinare C> 
-  * ultima ​coloana contine toti coeficientii ​$c_k$ intrucat ​$dp[i] = \sum_{k=1}^{KMAX} c_k * dp[i - k]$ +  * ultima ​coloană conține toți coeficienții ​$c_k$ întrucât ​$dp[i] = \sum_{k=1}^{KMAX} c_k * dp[i - k]$ 
-  * celelalte coloane ​contin ​doar cate o valoare ​nenula +  * celelalte coloane ​conțin ​doar câte o valoare ​nenulă 
-    * pe coloana j  vom avea valoarea 1 pe linia $j+1$ ($j = 1 : KMAX - 1$) +    * pe coloana j vom avea valoarea 1 pe linia $j + 1$ ($j = 1 : KMAX - 1$) 
-      * cum obtinem, de exemplu, $dp[i - 1]$? +      * cum obținem, de exemplu, $dp[i - 1]$? 
-      * pai avem $dp[i-1]$ chiar si in starea $S_{i-1}$, deci trebuie ​sa il copiam in starea $S_i$  +      * păi, avem $dp[i-1]$ chiar și în starea $S_{i-1}$, deci trebuie ​să îl copiem în starea $S_i$  
-        * copierea se realizeaza ​prin inmultirea ​cu 1 +        * copierea se realizează ​prin inmulțirea ​cu 1 
-        * daca $dp[i-1]$ era pe ultima ​pozitiei ​(pozitia ​k) in starea $S_{i-1}$, ​in noua stare $S_i$ este pe penultima ​pozitie ​(pozitia ​$k-1$) +        * dacă $dp[i-1]$ era pe ultima ​poziție ​(poziția ​k) în starea $S_{i-1}$, ​în noua stare $S_i$ este pe penultima ​poziție ​(poziția ​$k-1$) 
-          * deci s-a deplasat la stanga ​cu o pozitie!  +          * deci s-a deplasat la stânga ​cu o poziție!  
-    * in noua stare, noua pozitie ​este deplasata ​cu o unitate la stanga fata de starea ​precedenta +    * în noua stare, noua poziție ​este deplasată ​cu o unitate la stânga față ​de starea ​precedentă 
-      * de aceea pe coloana $j$, vrem sa avem elementul 1 pe linia $j + 1$ ($j = 1 : KMAX - 1$) +      * de aceeape coloana $j$, vrem să avem elementul 1 pe linia $j + 1$ ($j = 1 : KMAX - 1$) 
-      * cand inmultim ​$S_{i-1}$ cu coloana $C_j$ **dorim ​sa** +      * când înmulțim ​$S_{i-1}$ cu coloana $C_j$ **dorim ​** 
-        * ce copiam+        * ce copiem
-          * valoarea $dp[i - KMAX + j]$ din $S_{i-1}$ ​in $S_{i}$ +          * valoarea $dp[i - KMAX + j]$ din $S_{i-1}$ ​în $S_{i}$ 
-          * adica sa copiam ​a j-a valoare de pe linie  +          * adică să copiem ​a j-a valoare de pe linie  
-        * unde copiam+        * unde copiem
-          * de pe pozitia ​$j + 1$ pe pozitia ​$j$  ​+          * de pe poziția ​$j + 1$ pe poziția ​$j$  ​
 </​spoiler>​ </​spoiler>​
  
-== Exponentiere logaritmica ​pe matrice == +== Exponențiere logaritmică ​pe matrice == 
-Algoritmul naiv de mai sus are dezavantajul ​ca are tot o complexitate ​temporala ​$O(n)$.+Algoritmul naiv de mai sus are dezavantajul ​că are tot o complexitate ​temporală ​$O(n)$.
  
-Sa executam cativa pasi de inductie ​pentru a vedea cum este determinat $S_i$.+Să executăm câțiva pași de inducție ​pentru a vedea cum este determinat $S_i$.
 $$S_i = S_{i-1}C$$ $$S_i = S_{i-1}C$$
 $$S_i = S_{i-2}C^2$$ $$S_i = S_{i-2}C^2$$
Line 511: Line 499:
  
  
-In laboratorul 2 (Divide et Impera) am invatat ca putem calcula $ x ^ n $ in timp logaritmic. Deoarece ​si inmultirea ​matricilor este asociativa, putem calcula $C ^ n$ in timp logaritmic.+În laboratorul 2 (Divide et Impera) am învățat că putem calcula $x ^ n$ în timp logaritmic. Deoarece ​și înmulțirea ​matricilor este asociativă, putem calcula $C ^ n$ in timp logaritmic.
  
-Obtinem ​astfel o solutie ​cu urmatoarele complexitati+Obținem ​astfel o soluție ​cu următoarele complexități
-  * ** complexitate ​temporala ​**: $T = O(KMAX^3 * log(n))$ +  * ** complexitate ​temporală ​**: $T = O(KMAX^3 * log(n))$ 
-    * explicatie ​ +    * explicație ​ 
-      * facem doar $O(log n)$ pasi, dar un pas implica inmultire ​de matrice +      * facem doar $O(log n)$ pași, dar un pas implică înmulțire ​de matrice 
-      * o inmultire ​de matrice ​patratica ​de dimensiune KMAX are $KMAX^3$ ​operatii +      * o înmulțire ​de matrice ​patrătică ​de dimensiune KMAX are $KMAX^3$ ​operații 
-    * aceasta metoda ​este eficienta cand $KMAX << n$ (KMAX este mult mai mic decat n) +    * această metodă ​este eficientă când $KMAX << n$ (KMAX este mult mai mic decât ​n) 
-  * ** complexitatea ​spatiala ​**: $S = O(KMAX^3)$  +  * ** complexitatea ​spațială ​**: $S = O(KMAX^2)$  
-    explicatie  +**Observație!** În ultimele calcule nu am șters constanta ​KMAX, întrucât ​apare la puterea a 2-a! $KMAX = 1000implică ​$KMAX^= 10^6$, valoare care nu mai poate fi ignorată în practică ​($KMAX^2$ poate fi comparabil cu n).
-      ​este nevoie sa stocam cateva matrici +
-ObservatieIn ultimele calcule nu am sters contanta ​KMAX, intrucat ​apare la puterea a 3-a! $KMAX = 100implica ​$KMAX^= 10^6$, valoare care nu mai poate fi ignorata in practica ​($KMAX^3$ poate fi comparabil cu n).+
  
 === Gardurile lui Gigel (optimizare) === === Gardurile lui Gigel (optimizare) ===
-Dupa cum am vazut mai sus, in problema cu garduri ​data de Gigel solutia ​este o recurenta liniara:+După cum am văzut ​mai sus, în problema cu garduri ​dată de Gigel, soluția ​este o recurență liniară:
   *  $dp[1] = dp[2] = dp[3] = 1$; $d[4]=2$;   *  $dp[1] = dp[2] = dp[3] = 1$; $d[4]=2$;
   *  $dp[i] = dp[i - 1] + dp[i - 4]$, pentru $i > 4$   *  $dp[i] = dp[i - 1] + dp[i - 4]$, pentru $i > 4$
  
-== Exponentiere rapida ​==+== Exponențiere rapidă ​==
   * $ k = 4 $   * $ k = 4 $
-  * $S_4 = (dp[1], dp[2], dp[3], dp[4]) = (1, 1, 1, 4)$+  * $S_4 = (dp[1], dp[2], dp[3], dp[4]) = (1, 1, 1, 2)$
   * $S_i = (dp[i-3], dp[i-2], dp[i-1], dp[i])$   * $S_i = (dp[i-3], dp[i-2], dp[i-1], dp[i])$
-  * Raspunsul ​se afla efectuand operatia ​$S_n = S_4 * C^{n - 4}$, unde C are urmatorul continut:  ​+  * Răspunsul ​se află efectuând operația ​$S_n = S_4 * C^{n - 4}$, unde C are următorul conținut:  ​
 \begin{gather} ​ \begin{gather} ​
    C = \begin{bmatrix}    C = \begin{bmatrix}
Line 543: Line 529:
 \end{gather} \end{gather}
  
-<spoiler Implementare ​in C++> +<spoiler Implementare ​în C++> 
-Mai jos se afla o implementare ​simplista in C++ care cuprinde toate etapele pe care trebuie ​sa le realizati in cod, dupa ce stiti cum arata recurenta ​sub forma matriceala.+Mai jos se află o implementare ​simplistă în C++ care cuprinde toate etapele pe care trebuie ​să le realizați în cod, după ce știți ​cum arată recurența ​sub forma matriceală.
    
 <code cpp> <code cpp>
Line 558: Line 544:
     for (int i = 0; i < KMAX; ++i) {     for (int i = 0; i < KMAX; ++i) {
         for (int j = 0; j < KMAX; ++j) {         for (int j = 0; j < KMAX; ++j) {
-            unsigned long long sum = 0; // presupun ​ca suma  ​incape ​pe 64 de biti+            unsigned long long sum = 0; // presupun ​că suma încape ​pe 64 de biți
  
             for (int k = 0; k < KMAX; ++k) {             for (int k = 0; k < KMAX; ++k) {
Line 585: Line 571:
         if  (p % 2 == 0) {         if  (p % 2 == 0) {
             multiply_matrix(C,​ C, C);     // C = C*C             multiply_matrix(C,​ C, C);     // C = C*C
-            p /= 2;                       // ​ramane ​de calculat C^(p/2)+            p /= 2;                       // ​rămâne ​de calculat C^(p/2)
         } else {         } else {
             // reduc la cazul anterior:             // reduc la cazul anterior:
             multiply_matrix(tmp,​ C, tmp); // tmp = tmp*C             multiply_matrix(tmp,​ C, tmp); // tmp = tmp*C
-            --p;                          // ramane ​de calculat C^(p-1)+            --p;                          // rămâne ​de calculat C^(p-1)
         }         }
     }     }
  
-    // avem o parte din rezultat ​in si o parte in tmp+    // avem o parte din rezultat ​în și o parte în tmp
     multiply_matrix(C,​ tmp, R);           // rezultat = tmp * C     multiply_matrix(C,​ tmp, R);           // rezultat = tmp * C
 } }
  
 int garduri_rapide(int n) { int garduri_rapide(int n) {
-    // cazurile de baza+    // cazurile de bază
     if (n <= 3) return 1;     if (n <= 3) return 1;
     if (n == 4) return 2;     if (n == 4) return 2;
Line 607: Line 593:
                           {0, 1, 0, 0},                           {0, 1, 0, 0},
                           {0, 0, 1, 1}};                           {0, 0, 1, 1}};
-   // vreau sa aplic formula S_n = S_4 * C^(n-4)+   // vreau să aplic formula S_n = S_4 * C^(n-4)
  
    // C = C^(n-4)    // C = C^(n-4)
    ​power_matrix(C,​ n - 4, C);    ​power_matrix(C,​ n - 4, C);
  
-   // sol = S_4 * C = dp[n] (se afla pe ultima ​pozitie ​din S_n, +   // sol = S_4 * C = dp[n] (se află pe ultima ​poziție ​din S_n, 
-   // deci voi folosi ultima ​coloana ​din C)+   // deci voi folosi ultima ​coloană ​din C)
    int sol = 1 * C[0][3] + 1 * C[1][3] + 1 * C[2][3] + 2 * C[3][3];    int sol = 1 * C[0][3] + 1 * C[1][3] + 1 * C[2][3] + 2 * C[3][3];
    ​return sol % MOD;    ​return sol % MOD;
Line 621: Line 607:
  
 <​note>​ <​note>​
-Remarcati ​faptul ​ca in functia ​de inmultire ​se foloseste ​o matrice ​temporara ​$tmp$. Motivul este ca vrem sa apelam functia ​$multiply(C,​ C, C)$, unde C joaca atat rol de intrare ​cat si de iesireDaca am pune rezultatele direct in C, atunci am strica inputul ​inainte sa obtinem ​rezultatul.+Remarcați ​faptul ​că în funcția ​de înmulțire ​se folosește ​o matrice ​temporară ​$tmp$. Motivul este că vrem să apelăm funcția ​$multiply(C,​ C, C)$, unde C joacă atât rol de intrare ​cât și de ieșireDacă am pune rezultatele direct in C, atunci am strica inputul ​înainte să obținem ​rezultatul.
  
-Putem spune ca acea functie ​este **matrix_multiply_safe**, ​in sensul ​ca pentru orice A,B,C care respecta ​dimensiunile impuse, ​functia ​va calcula corect produsul.+Putem spune că acea funcție ​este **matrix_multiply_safe**, ​în sensul ​că pentru orice A,B,C care respectă ​dimensiunile impuse, ​funcția ​va calcula corect produsul.
  
 </​note>​ </​note>​
 </​spoiler>​ </​spoiler>​
  
-<​spoiler ​Comparatie ​solutii (studiu de caz pentru ​curiosi)> +<​spoiler ​Comparație ​solutii (studiu de caz pentru ​curioși)> 
-In arhiva ** demo-lab04.zip ** gasiti ​sursa completa in care se realizeaza+Pe git găsiți ​sursă completă în care se realizează
-  * o verificare a faptului ​ca cele 2 implementari ​(** gardurile_lui_Gigel** ​si **garduri_rapide**) produc ​aceleasi ​rezultate +  * o verificare a faptului ​că cele 2 implementări ​(** gardurile_lui_Gigel** ​și **garduri_rapide**) produc ​aceleași ​rezultate 
-  * un benchmark ​in care cele 2 implementari ​sunt comparate +  * un benchmark ​în care cele 2 implementări ​sunt comparate 
-    * pe sistem uzual (laptop) s-au obtinut urmatoarele ​rezulate:+    * pe un sistem uzual (laptop) s-au obținut următoarele ​rezulate:
 <code bash> <code bash>
-test case: varianta ​simpla+test case: varianta ​simplă
 n = 100000000 sol = 119; time = 0.984545 s n = 100000000 sol = 119; time = 0.984545 s
-test case: varianta ​rapida+test case: varianta ​rapidă
 n = 100000000 sol = 119; time = 0.000021 s n = 100000000 sol = 119; time = 0.000021 s
  
  
-test case: varianta ​simpla+test case: varianta ​simplă
 n = 1000000000 sol = 812; time = 9.662377 s n = 1000000000 sol = 812; time = 9.662377 s
-test case: varianta ​rapida+test case: varianta ​rapidă
 n = 1000000000 sol = 812; time = 0.000022 s n = 1000000000 sol = 812; time = 0.000022 s
 </​code> ​ </​code> ​
-     * se observa ​clar diferenta intre cele 2 solutii ​(am confirmat ceea ce spunea ​si teoria: $O(n) $ vs $O(log(n))$); ​aceasta tehnica imbunatateste ​drastic o solutie gasita ​relativ usor.+     * se observă ​clar diferența între ​cele 2 soluții ​(am confirmat ceea ce spunea ​și teoria: $O(n) $ vs $O(log(n))$); ​această tehnică îmbunătățește ​drastic o soluție gasită ​relativ usor.
  
 </​spoiler>​ </​spoiler>​
    
-===== Exercitii ​=====+===== Exerciții ​=====
 <​note>​ <​note>​
 Scheletul de laborator se găsește pe pagina [[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​skel/​lab04|pa-lab::​skel/​lab04]]. Scheletul de laborator se găsește pe pagina [[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​skel/​lab04|pa-lab::​skel/​lab04]].
 </​note>​ </​note>​
 === DP or math? === === DP or math? ===
-Fie un sir de **numere naturale strict pozitive**. ​Cate **subsiruri** (submultimi ​nevide) au suma numerelor **para**?+Fie un șir de **numere naturale strict pozitive**. ​Câte **subșiruri** (submulțimi ​nevide) au suma numerelor **pară**?
  
 <​note>​ <​note>​
-**subsir** (**subsequence** ​in engleza) pentru un vector ** v **inseamna ​un alt vector $u = [v[i_1], v[i_2],..., v[i_k]]]$ unde $i_1 < i_2 < ... < i_k$.+**subșir** (**subsequence** ​în engleză) pentru un vector **v** înseamnă ​un alt vector $u = [v[i_1], v[i_2],..., v[i_k]]]$ unde $i_1 < i_2 < ... < i_k$.
 </​note>​ </​note>​
  
  
 Task-uri: Task-uri:
-  * Se cere o **solutie ​folosind DP**. +  * Se cere o **soluție ​folosind DP**. 
-  * Inspectand recurenta gasita ​la punctul precedent, ​incercati sa inlocuiti ​cu o **formula matematica**. +  * Inspectând recurența gasită ​la punctul precedent, ​încercați să înlocuiți ​cu o **formulă matematică**. 
-  * Care este **complexitatea** pentru fiecare ​solutie ​(timp + spatiu)? Care este mai buna? De ce? :D+  * Care este **complexitatea** pentru fiecare ​soluție ​(timp + spațiu)? Care este mai bună? De ce? :D
  
-Deoarece rezultatul poate fi prea mare, se cere **restul ​impartirii** lui la $1000000007$ ($10^9 + 7$).+Deoarece rezultatul poate fi prea mare, se cere **restul ​împărțirii** lui la $1000000007$ ($10^9 + 7$).
  
-Pentru punctaj maxim pentru ​aceasta problema, este necesar ​sa rezolvati ​toate subpunctele (ex. nu folositi ​direct formula, ​gasiti ​mai intai recurenta ​DP). Trebuie ​sa implementati ​**cel putin** solutia ​cu DP.+Pentru punctaj maxim pentru ​această problemă, este necesar ​să rezolvați ​toate subpunctele (ex. nu folosiți ​direct formula, ​găsiți ​mai întâi recurența ​DP). Trebuie ​să implementați ​**cel puțin** soluția ​cu DP.
  
  
Line 676: Line 662:
 |v|2|6|4| |v|2|6|4|
  
-Raspuns: $7$+Răspuns: $7$
  
-Explicatie: Toate subsirurile ​posibile sunt+Explicație: Toate subșirurile ​posibile sunt
   * $[2]$   * $[2]$
   * $[2, 6]$   * $[2, 6]$
Line 686: Line 672:
   * $[6, 4]$   * $[6, 4]$
   * $[4]$   * $[4]$
-Toate subsirurile ​de mai sus au suma para.+Toate subșirurile ​de mai sus au suma pară.
 </​spoiler>​ </​spoiler>​
  
Line 695: Line 681:
 |v|2|1|3| |v|2|1|3|
  
-Raspuns: $3$+Răspuns: $3$
  
-Explicatie: Toate subsirurile ​posibile sunt+Explicație: Toate subșirurile ​posibile sunt
   * $[2]$   * $[2]$
   * $[2, 1]$   * $[2, 1]$
Line 706: Line 692:
   * $[3]$   * $[3]$
  
-Subsirurile ​cu suma para sunt: $[2]$, $[2, 1, 3]$, $[1, 3]$.+Subșirurile ​cu sumă pară sunt: $[2]$, $[2, 1, 3]$, $[1, 3]$.
  
 </​spoiler>​ </​spoiler>​
Line 716: Line 702:
 |v|3|2|1| |v|3|2|1|
  
-Raspuns: $3$+Răspuns: $3$
  
-Explicatie: Toate subsirurile ​posibile sunt+Explicație: Toate subșirurile ​posibile sunt
   * $[3]$   * $[3]$
   * $[3, 2]$   * $[3, 2]$
Line 727: Line 713:
   * $[1]$   * $[1]$
  
-Subsirurile ​cu suma para sunt: $[3, 2, 1]$, $[3, 1]$, $[2]$.+Subșirurile ​cu sumă pară sunt: $[3, 2, 1]$, $[3, 1]$, $[2]$.
  
 </​spoiler>​ </​spoiler>​
Line 734: Line 720:
 Morala: există probleme pentru care găsim o soluție cu DP, dar pentru care pot exista și alte soluții mai bune (am ignorat citirea/​afișarea). Morala: există probleme pentru care găsim o soluție cu DP, dar pentru care pot exista și alte soluții mai bune (am ignorat citirea/​afișarea).
  
-In problemele de numaratexista ​o **sansa** buna sa putem gasi (si) o formula matematicacare poate fi implementata intr-un mod mai eficient ​decat recurenta ​DP. +În problemele de număratexistă ​o **șansă** bună să putem si (și) o formulă matematicăce poate fi implementată într-un mod mai eficient ​decât ​recurență ​DP. 
 </​note>​ </​note>​
  
 <spoiler Hint> <spoiler Hint>
-Cate subsiruri ​au suma **impara**?+Câte subșiruri ​au suma **impară**?
 </​spoiler>​ </​spoiler>​
  
 <​hidden>​ <​hidden>​
-<​spoiler ​Solutie+<​spoiler ​Soluție
-Problema este preluata ​de [[https://​infoarena.ro/​problema/​azerah|aici]]. ​Solutia ​se gaseste ​[[https://​www.infoarena.ro/​onis-2015/​solutii-runda-1#​azerah|aici]].+Problema este preluată ​de [[https://​infoarena.ro/​problema/​azerah|aici]]. ​Soluția ​se găsește ​[[https://​www.infoarena.ro/​onis-2015/​solutii-runda-1#​azerah|aici]].
 </​spoiler>​ </​spoiler>​
 </​hidden>​ </​hidden>​
  
-=== Expresie ​booleana ​=== +=== Expresie ​booleană ​=== 
-Se da o expresie ​booleana corecta ​cu n termeni. Fiecare din termeni poate fi unul din stringurile **true**, **false**, **and**, **or**, **xor**.+Se dă o expresie ​booleană corectă ​cu n termeni. Fiecare din termeni poate fi unul din stringurile **true**, **false**, **and**, **or**, **xor**.
  
-Numarati ​modurile ​in care se pot aseza paranteze astfel ​incat rezultatul ​sa fie **true**. Se respecta ​regulile de la logica ​(tabelele de adevar ​pentru ​operatiile ​**and**, **or**, **xor**).+Numărați ​modurile ​în care se pot așeza ​paranteze astfel ​încât ​rezultatul ​să fie **true**. Se respectă ​regulile de la logică ​(tabelele de adevăr ​pentru ​operațiile ​**and**, **or**, **xor**).
  
-Deoarece rezultatul poate fi prea mare, se cere **restul ​impartirii** lui la $1000000007$ ($10^9 + 7$).+Deoarece rezultatul poate fi prea mare, se cere **restul ​împărțirii** lui la $1000000007$ ($10^9 + 7$).
  
 <​note>​ <​note>​
-In schelet vom codifica cu valori de tip char cele 5 stringuri:+În schelet vom codifica cu valori de tip char cele 5 stringuri:
   * **false**: '​F'​   * **false**: '​F'​
   * **true**: '​T'​   * **true**: '​T'​
Line 762: Line 748:
   * **xor**: '​^'​   * **xor**: '​^'​
  
-Functia ​pe care va trebui ​sa implementati ​voi va folosi variabilele **n** (numarul ​de termeni) ​si ** expr** (vectorul cu termenii expresiei).+Funcția ​pe care va trebui ​să implementați ​voi va folosi variabilele **n** (numărul ​de termeni) ​și **expr** (vectorul cu termenii expresiei).
 </​note>​ </​note>​
  
  
 <spoiler Exemplu 1> <spoiler Exemplu 1>
-$n = 5$ si $expr = ['​T',​ '&',​ '​F',​ '​^',​ '​T'​]$ (expr = [** true and false xor true**])+$n = 5$ și $expr = ['​T',​ '&',​ '​F',​ '​^',​ '​T'​]$ (expr = [** true and false xor true**])
  
-Raspuns: $2$+Răspuns: $2$
  
-ExplicatieExista ​2 moduri corecte de a paranteza expresia astfel ​incat sa obtinem ​rezultatul **true** (1).+ExplicațieExistă ​2 moduri corecte de a paranteza expresia astfel ​încât să obținem ​rezultatul **true** (1).
   * $ T&(F^T) $   * $ T&(F^T) $
   * $ (T&F)^T $   * $ (T&F)^T $
Line 777: Line 763:
  
 <spoiler Hint> <spoiler Hint>
-    Complexitate temporală ​dorita ​este $O(n ^ 3)$.+    Complexitate temporală ​dorită ​este $O(n ^ 3)$.
     ​     ​
-    ​Optional, se pot defini ​functii ajutatoare ​precum **is_operand**,​ **is_operator**,​ **evaluate**.+    ​Opțional, se pot defini ​funcții ajutătoare ​precum **is_operand**,​ **is_operator**,​ **evaluate**.
 </​spoiler>​ </​spoiler>​
  
 <note tip> <note tip>
-Pentru rezolvarea celor doua probleme ​ganditi-va la ce scrie in sectiunea ​[[http://​ocw.cs.pub.ro/​courses/​pa/​laboratoare/​laborator-04?&#​sfaturireguli| Sfaturi / Reguli]]. Pentru fiecare dintre cele doua probleme facem o **partitionare dupa un anumit criteriu**.+Pentru rezolvarea celor două probleme ​gândiți-vă la ce scrise în secțiunea ​[[http://​ocw.cs.pub.ro/​courses/​pa/​laboratoare/​laborator-04?&#​sfaturireguli| Sfaturi / Reguli]]. Pentru fiecare dintre cele două probleme facem o **partiționare după un anumit criteriu**.
  
  
-Pentru problema** DP or math?​** ​partitionam ​toate subsirurile dupa critieriul **paritatii ​sumei subsirului** (cate sunt pare/​impare).\\  +Pentru problema **DP or math?​** ​partiționăm ​toate subșirurile după critieriul **parității ​sumei subșirului** (câte sunt pare/​impare).\\  
-Pentru problema **expresie ​booleana** partitionam ​**toate ​parantezarile ​posibile ​dupa rezultatul lor** (cate dau true/​false).+Pentru problema **expresie ​booleană** partiționăm ​**toate ​parantezările ​posibile ​după rezultatul lor** (câte dau true/​false).
  
 </​note>​ </​note>​
 === Bonus === === Bonus ===
-Asistentul va alege una dintre problemele din sectiunea ​Extra.+Asistentul va alege una dintre problemele din secțiunea ​Extra.
  
 <spoiler Hint> <spoiler Hint>
-Recomandam sa ** NU** fie una din cele 3 probleme de la Test PA 2017. Recomandam sa le incercati dupa ce recapitulati acasa DP1 si DP2, pentru a verifica ​daca cunostintele ​acumulate sunt la nivelul ​asteptat.+Recomandăm să **NU** fie una dintre ​cele 3 probleme de la Test PA 2017. Recomandăm să le incercați după ce recapitulați acasă ​DP1 și DP2, pentru a verifica ​dacă cunoștințele ​acumulate sunt la nivelul ​așteptat.
 </​spoiler>​ </​spoiler>​
  
 === Extra === === Extra ===
-<​spoiler ​Extraterestrii+<​spoiler ​Extratereștrii
-Rezolvati ​problema [[https://​www.hackerrank.com/​contests/​test-practic-pa-2017-v1-plumbus/​challenges/​test-1-extraterestrii +Rezolvați ​problema [[https://​www.hackerrank.com/​contests/​test-practic-pa-2017-v1-plumbus/​challenges/​test-1-extraterestrii 
-extraterestrii]] de la Test PA 2017.+extratereștrii]] de la Test PA 2017.
 </​spoiler>​ </​spoiler>​
  
-<​spoiler ​Secvente+<​spoiler ​Secvențe
-Rezolvati ​problema [[https://​www.hackerrank.com/​contests/​test-practic-pa-2017-v1-plumbus/​challenges/​test-1-secvente +Rezolvați ​problema [[https://​www.hackerrank.com/​contests/​test-practic-pa-2017-v1-plumbus/​challenges/​test-1-secvente 
-Secvente]] de la Test PA 2017.+Secvențe]] de la Test PA 2017.
 </​spoiler>​ </​spoiler>​
  
Line 811: Line 797:
  
 <spoiler PA Country> <spoiler PA Country>
-Rezolvati ​problema [[https://​www.hackerrank.com/​contests/​test-practic-pa-2017-v2-meeseeks/​challenges/​test-2-pa-country-medie+Rezolvați ​problema [[https://​www.hackerrank.com/​contests/​test-practic-pa-2017-v2-meeseeks/​challenges/​test-2-pa-country-medie
 | PA Country]] de la Test PA 2017. | PA Country]] de la Test PA 2017.
 </​spoiler>​ </​spoiler>​
Line 819: Line 805:
    
 <spoiler iepuri> <spoiler iepuri>
-Rezolvati ​pe infoarena problema [[http://​infoarena.ro/​problema/​iepuri| iepuri]].+Rezolvați ​pe infoarena problema [[http://​infoarena.ro/​problema/​iepuri| iepuri]].
  
-Hint: Exponentiere logaritmica ​pe matrice+Hint: Exponențiere logaritmică ​pe matrice
  
-Solutie:+Soluție:
   * $dp[0] = X; dp[1] = Y; dp[0] = Z; $   * $dp[0] = X; dp[1] = Y; dp[0] = Z; $
   * $dp[i] = (A * dp[i-1] + B * dp[i-2] + C * dp[i-3]) \ \% \ 666013$   * $dp[i] = (A * dp[i-1] + B * dp[i-2] + C * dp[i-3]) \ \% \ 666013$
  
-Pentru punctaj maxim, pentru fiecare test se foloseste ecuatia matriceala atasata.+Pentru punctaj maxim, pentru fiecare test se folosește ecuația matriceală atașată.
 Complexitate:​ $O(T * log(n))$. Complexitate:​ $O(T * log(n))$.
  
Line 834: Line 820:
  
 <spoiler Minimum Path Sum> <spoiler Minimum Path Sum>
-Rezolvati ​pe leetcode problema [[https://​leetcode.com/​problems/​minimum-path-sum/​description/#​| Minimum Path Sum]].+Rezolvați ​pe leetcode problema [[https://​leetcode.com/​problems/​minimum-path-sum/​description/#​| Minimum Path Sum]].
 </​spoiler>​ </​spoiler>​
  
  
-<​spoiler ​Lacusta+<​spoiler ​Lăcusta
-Rezolvati ​pe infoarena problema [[http://​infoarena.ro/​problema/​Lacusta| ​Lacusta]].+Rezolvați ​pe infoarena problema [[http://​infoarena.ro/​problema/​Lacusta| ​Lăcusta]].
 </​spoiler>​ </​spoiler>​
  
  
 <spoiler Suma4> <spoiler Suma4>
-Rezolvati ​pe infoarena problema [[http://​infoarena.ro/​problema/​Suma4|Suma4]].+Rezolvați ​pe infoarena problema [[http://​infoarena.ro/​problema/​Suma4|Suma4]].
 </​spoiler>​ </​spoiler>​
  
-<​spoiler ​Subsir+<​spoiler ​Subșir
-Rezolvati ​pe infoarena problema [[https://​www.infoarena.ro/​problema/​subsir|subsir]].+Rezolvați ​pe infoarena problema [[https://​www.infoarena.ro/​problema/​subsir|subșir]].
 </​spoiler>​ </​spoiler>​
  
-<​spoiler ​2sah+<​spoiler ​2șah
-Rezolvati ​pe infoarena problema [[https://​infoarena.ro/​problema/​2sah | 2sah]].+Rezolvați ​pe infoarena problema [[https://​infoarena.ro/​problema/​2sah | 2șah]].
  
-Hint:   Exponentiere logaritmica ​pe matrice+Hint: Exponențiere logaritmică ​pe matrice
  
-descrie detaliata ​se afla in [[http://​olimpiada.info/​oji2015/​index.php?​cid=arhiva | arhiva OJI 2015]].+descriere detaliată ​se află în [[http://​olimpiada.info/​oji2015/​index.php?​cid=arhiva | arhiva OJI 2015]].
 </​spoiler>​ </​spoiler>​
  
Line 865: Line 851:
 ===== Referințe ===== ===== Referințe =====
  
-[0] Capitolul ​**Dynamic Programming** ​din **Introductions ​to Algorithms** de către T. H. Cormen, ​C. E. Leiserson, ​R. L. Rivest, C. Stein +[0] Chapter ​**Dynamic Programming**, “Introduction ​to Algorithms”, Thomas ​H. Cormen, ​Charles ​E. Leiserson, ​Ronald ​L. Rivest ​and Clifford ​Stein 
 + 
 [1] [[http://​infoarena.ro/​problema/​podm]] [1] [[http://​infoarena.ro/​problema/​podm]]
  
pa/laboratoare/laborator-04.1615790996.txt.gz · Last modified: 2021/03/15 08:49 by miruna_elena.banu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0