This shows you the differences between two versions of the page.
|
pa:laboratoare:laborator-02 [2026/03/09 23:55] radu.nichita [Pool probleme (pentru prezentări)] |
pa:laboratoare:laborator-02 [2026/03/15 19:10] (current) aureliu.antonie [Gardurile lui Gigel] |
||
|---|---|---|---|
| Line 7: | Line 7: | ||
| ===== Precizări inițiale ===== | ===== Precizări inițiale ===== | ||
| <note> | <note> | ||
| - | Toate exemplele de cod se găsesc pe pagina [[https://github.com/acs-pa/pa-lab/tree/main/demo/lab04|pa-lab::demo/lab04]]. | + | Toate exemplele de cod se găsesc pe pagina [[https://github.com/acs-pa/pa-lab/tree/main/algorithms/lab02|pa-lab/algorithms/lab02]]. |
| - | Exemplele de cod apar încorporate și în textul laboratorului pentru a facilita parcurgerea cursivă a acestuia. **ATENȚIE!** Varianta actualizată a acestor exemple se găsește întotdeauna pe GitHub. | + | Exemplele de cod apar încorporate și în textul laboratorului pentru a facilita parcurgerea cursivă a acestuia. ATENȚIE! Varianta actualizată a acestor exemple se găsește întotdeauna pe GitHub. |
| </note> | </note> | ||
| - | * Toate bucățile de cod prezentate în partea introductivă a laboratorului (înainte de exerciții) au fost testate. Cu toate acestea, este posibil ca, din cauza mai multor factori (formatare, caractere invizibile puse de browser, etc.), un simplu copy-paste să nu fie de ajuns pentru a compila codul. | + | * Toate bucățile de cod prezentate în partea introductivă a laboratorului (înainte de exerciții) au fost testate. Cu toate acestea, este posibil ca din cauza mai multor factori (formatare, caractere invizibile puse de browser etc) un simplu copy-paste să nu fie de ajuns pentru a compila codul. |
| * Vă rugăm să compilați **DOAR** codul de pe GitHub. Pentru raportarea problemelor, contactați unul dintre maintaineri. | * Vă rugăm să compilați **DOAR** codul de pe GitHub. Pentru raportarea problemelor, contactați unul dintre maintaineri. | ||
| * Pentru orice problemă legată de conținutul acestei pagini, vă rugam să dați e-mail unuia dintre responsabili. | * Pentru orice problemă legată de conținutul acestei pagini, vă rugam să dați e-mail unuia dintre responsabili. | ||
| Line 23: | Line 23: | ||
| De asemenea, DP se poate folosi și pentru probleme în care nu căutam un optim, cum ar fi **problemele de numărare**. | De asemenea, DP se poate folosi și pentru probleme în care nu căutam un optim, cum ar fi **problemele de numărare**. | ||
| - | Pentru noțiunile prezentate până acum despre DP, vă rugăm să consultați pagina laboratorului 3. | + | Pentru noțiunile prezentate până acum despre DP, vă rugăm să consultați pagina [[pa:laboratoare:laborator-01|laboratorului 01]]. |
| ===== Exemple clasice ===== | ===== Exemple clasice ===== | ||
| Line 61: | Line 61: | ||
| == Enunț == | == Enunț == | ||
| - | Fie un produs matriceal $M = M_1 M_2 ... M_n$. Putem pune paranteze în mai multe moduri și vom obține același rezultat (înmulțire asociativă), dar este posibil să obținem un număr diferit de **înmulțiri scalare**. | + | Fie un produs matriceal $M = M_1 M_2 ... M_n$. Putem pune paranteze în mai multe moduri și vom obține același rezultat (înmulțirea este asociativă), dar este posibil să obținem un număr diferit de **înmulțiri scalare**. |
| Matricea $M_i$ are (prin convenție), dimensiunile $d_{i-1} d_{i}$. | Matricea $M_i$ are (prin convenție), dimensiunile $d_{i-1} d_{i}$. | ||
| Line 359: | Line 359: | ||
| * $dp[i] = (dp[i-1] + dp[i-4]) \ \% \ MOD$ | * $dp[i] = (dp[i-1] + dp[i-4]) \ \% \ MOD$ | ||
| * | * | ||
| - | <note> Așa cum am zis în secțiunea de [[http://ocw.cs.pub.ro/courses/pa/laboratoare/laborator-04?&#sfaturireguli|sfaturi și reguli]] vrem să facem o **parționare** după un anumit **criteriu**: în cazul problemei de față, criteriul de parționare este dacă gardul se termină cu o scândură verticală sau orizontală. | + | <note> Așa cum am zis în secțiunea de [[http://ocw.cs.pub.ro/courses/pa/laboratoare/laborator-02?&#sfaturireguli|sfaturi și reguli]] vrem să facem o **parționare** după un anumit **criteriu**: în cazul problemei de față, criteriul de parționare este dacă gardul se termină cu o scândură verticală sau orizontală. |
| - | De asemenea, tot în secțiunea [[http://ocw.cs.pub.ro/courses/pa/laboratoare/laborator-04?&#sfaturireguli|sfaturi și reguli]] am precizat că nu vrem **să număram un obiect** (un mod de a construi gardul) **de două ori**. Recurența noastră (dp[i] = dp[i-1] + dp[i-4]) nu ia un obiect de două ori pentru că orice soluție care vine din dp[i-4] e diferită de alta care vine din dp[i-1] pentru că diferă în cel puțin ultima scândură așezată) </note> | + | De asemenea, tot în secțiunea [[http://ocw.cs.pub.ro/courses/pa/laboratoare/laborator-02?&#sfaturireguli|sfaturi și reguli]] am precizat că nu vrem **să număram un obiect** (un mod de a construi gardul) **de două ori**. Recurența noastră (dp[i] = dp[i-1] + dp[i-4]) nu ia un obiect de două ori pentru că orice soluție care vine din dp[i-4] e diferită de alta care vine din dp[i-1] pentru că diferă în cel puțin ultima scândură așezată) </note> |
| == Implementare recurență == | == Implementare recurență == | ||
| Line 409: | Line 409: | ||
| De multe ori, este nevoie să folosim câteva tehnici pentru a obține performanța maximă cu recurența găsită. | De multe ori, este nevoie să folosim câteva tehnici pentru a obține performanța maximă cu recurența găsită. | ||
| - | În prima parte a laboratorului 3 se menționa tehnica de memoizare. În acesta, ne vom rezuma la cum putem folosi cunoștințele de lucru matriceal pentru a favoriza implementarea unor anumite tipuri de recurențe. | + | În prima parte a [[pa:laboratoare:laborator-01|laboratorului 01]] se menționa tehnica de **memoizare**. În acesta, ne vom rezuma la cum putem folosi cunoștințele de lucru matriceal pentru a favoriza implementarea unor anumite tipuri de recurențe. |
| ==== Exponențiere pe matrice pentru recurențe liniare ==== | ==== Exponențiere pe matrice pentru recurențe liniare ==== | ||
| Line 498: | Line 498: | ||
| $$S_i = S_{k}C^{i -k}$$ | $$S_i = S_{k}C^{i -k}$$ | ||
| + | Pentru a aduce un plus de viteză, vom folosi un truc numit [[https://en.wikipedia.org/wiki/Exponentiation_by_squaring|exponențiere rapidă]]. Pe scurt, vom ridica o valoare(notată $a$) la puterea n, împărțind n folosind reprezentarea sa binară. | ||
| - | Î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. | + | De exemplu, dacă am vrea să calculăm: |
| + | $$ 5^{13} = 5^{1101_2}= 5^8 * 5^4 * 5^1 $$ | ||
| + | |||
| + | Exponentul are exact $\lfloor log_2(n) \rfloor + 1$ cifre în baza 2, deci vom avea nevoie de $O(log(n))$ înmulțiri, fiind condiționați de faptul că trebuie să cunoaștem $a^1, a^2, a^4, etc.$ Din fericire, putem calcula rapid acești factori prin ridicarea la pătrat a elementului precedent. | ||
| + | |||
| + | În final, putem implementa un algoritm iterativ pentru calcularea rezultatului $a^n$ iterând prin cifrele din baza 2 ale lui n și înmulțind cu ${a^2}^{k}$ atunci când cifra curentă este 1(pentru viteză, vom folosi operații pe biți în loc de o iterare propriu zisă prin cifre). | ||
| + | |||
| + | Mai jos putem vedea o implementare in C++: | ||
| + | <code cpp> | ||
| + | long long pow(long long a, long long n) { | ||
| + | long long res = 1; | ||
| + | while (n > 0) { | ||
| + | // daca cel mai nesemnificativ bit(LSB) din n este 1 | ||
| + | if (n & 1) { | ||
| + | res = res * a; | ||
| + | } | ||
| + | |||
| + | // calculam urmatorul factor | ||
| + | a = a * a; | ||
| + | |||
| + | // shiftam la dreapta n cu o pozitie(urmatorul bit va deveni LSB) | ||
| + | n >>= 1; | ||
| + | } | ||
| + | return res; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Acest truc poate fi folosit pentru orice tip de date pentru care înmulțirea este asociativă(inclusiv matrice). | ||
| Obținem astfel o soluție cu următoarele complexități: | Obținem astfel o soluție cu următoarele complexități: | ||
| Line 643: | Line 671: | ||
| ===== Pool probleme (pentru prezentări) ====== | ===== Pool probleme (pentru prezentări) ====== | ||
| - | <hidden> | + | ======= 1) Rectangle Cutting ======= |
| - | + | ||
| - | ======= 1) Burst Balloons ======= | + | |
| - | + | ||
| - | **Enunt:** | + | |
| - | Se dau ''n'' baloane, fiecare având un număr asociat. Când se sparge balonul ''i'', se câștigă un număr de monede egale cu produsul numerelor de pe balonul ''i'' și baloanele vecine lui în acel moment. | + | |
| - | După spargere, balonul dispare, iar vecinii lui devin adiacenți. La extremități se consideră două baloane imaginare cu valoarea 1. | + | |
| - | + | ||
| - | Determinati numărul maxim de monede pe care îl puteți obține spargând toate baloanele într-o anumită ordine. | + | |
| - | + | ||
| - | **Date de intrare:** | + | |
| - | Un vector de ''n'' numere întregi care reprezintă valorile baloanelor. | + | |
| - | + | ||
| - | **Date de ieșire:** | + | |
| - | Se afișează un singur număr întreg — numărul maxim de monede ce poate fi obținut. | + | |
| - | + | ||
| - | Problema se poate testa la: | + | |
| - | https://leetcode.com/problems/burst-balloons/description/ | + | |
| - | + | ||
| - | ======= 2) Rectangle Cutting ======= | + | |
| **Enunt:** | **Enunt:** | ||
| Line 678: | Line 687: | ||
| https://cses.fi/problemset/task/1744 | https://cses.fi/problemset/task/1744 | ||
| - | ======= 3) Removal Game ======= | + | ======= 2) Removal Game ======= |
| **Enunt:** | **Enunt:** | ||
| Line 696: | Line 705: | ||
| https://cses.fi/problemset/task/1097/ | https://cses.fi/problemset/task/1097/ | ||
| - | ======= 4) Array Description ======= | + | ======= 3) Array Description ======= |
| **Enunt:** | **Enunt:** | ||
| Line 714: | Line 723: | ||
| https://cses.fi/problemset/task/1746/ | https://cses.fi/problemset/task/1746/ | ||
| - | ======= 5) Student Attendance Record II ======= | + | ======= 4) Student Attendance Record II ======= |
| **Enunt:** | **Enunt:** | ||
| Un elev are un istoric al prezentețor la școală pe parcursul a ''n'' zile. Pentru fiecare zi, status-ul său poate fi: | Un elev are un istoric al prezentețor la școală pe parcursul a ''n'' zile. Pentru fiecare zi, status-ul său poate fi: | ||
| - | - P (present) — prezent | + | * P (present) — prezent |
| - | - L (late) — întârziat | + | * L (late) — întârziat |
| - | - A (absent) — absent | + | * A (absent) — absent |
| Un istoric este considerat valid dacă: | Un istoric este considerat valid dacă: | ||
| - | - conține cel mult o absență (A) | + | * conține cel mult o absență (A) |
| - | - nu conține mai mult de două întârzii consecutive (L) | + | * nu conține mai mult de două întârzieri consecutive (L) |
| Determinati câte istorice de prezență valide de lungime ''n'' există. | Determinati câte istorice de prezență valide de lungime ''n'' există. | ||
| Line 737: | Line 746: | ||
| https://leetcode.com/problems/student-attendance-record-ii/description/ | https://leetcode.com/problems/student-attendance-record-ii/description/ | ||
| - | </hidden> | + | ======= 5) Burst Balloons ======= |
| + | |||
| + | **Enunt:** | ||
| + | Se dau ''n'' baloane, fiecare având un număr asociat. Când se sparge balonul ''i'', se câștigă un număr de monede egale cu produsul numerelor de pe balonul ''i'' și baloanele vecine lui în acel moment. | ||
| + | După spargere, balonul dispare, iar vecinii lui devin adiacenți. La extremități se consideră două baloane imaginare cu valoarea 1. | ||
| + | |||
| + | Determinati numărul maxim de monede pe care îl puteți obține spargând toate baloanele într-o anumită ordine. | ||
| + | |||
| + | **Date de intrare:** | ||
| + | Un vector de ''n'' numere întregi care reprezintă valorile baloanelor. | ||
| + | |||
| + | **Date de ieșire:** | ||
| + | Se afișează un singur număr întreg — numărul maxim de monede ce poate fi obținut. | ||
| + | |||
| + | Problema se poate testa la: | ||
| + | https://leetcode.com/problems/burst-balloons/description/ | ||
| ===== Extra (studiu de caz pentru acasă) ===== | ===== Extra (studiu de caz pentru acasă) ===== | ||
| <spoiler Por Costel si Azerath> | <spoiler Por Costel si Azerath> | ||