Differences

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

Link to this comparison view

pa:laboratoare:laborator-02 [2026/03/09 23:39]
radu.nichita [Exerciții]
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 cadin cauza mai multor factori (formatare, caractere invizibile puse de browseretc.)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 ​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 Imperaam învățat că putem calcula $^ n$ în timp logaritmic. Deoarece ​și înmulțirea matricilor ​este asociativă, putem calcula $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 641: Line 669:
  
  
-===== Exerciții ===== +===== Pool probleme (pentru prezentări) ======
-<​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]]. +
-</​note>​ +
-=== DP or math? === +
-Fie un șir de **numere naturale strict pozitive**. Câte **subșiruri** (submulțimi nevide) au suma numerelor **pară**?+
  
-<​note>​ +======= 1Rectangle Cutting =======
-**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>​+
  
 +**Enunt:​**  ​
 +Se dă un dreptunghi de dimensiuni ''​a × b''​. Se pot face tăieturi doar pe linii paralele cu laturile dreptunghiului,​ împărțind dreptunghiul în două dreptunghiuri mai mici.  ​
  
-Task-uri: +Determinati numărul minim de tăieturi necesare pentru ​împărți dreptunghiul în pătrate.
-  * Se cere o **soluție folosind DP**. +
-  * Inspectând recurențgasită la punctul precedent, încercați să o înlocuiți cu o **formulă matematică**. +
-  * 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 împărțirii** lui la $1000000007$ ($10^9 + 7$).+**Date de intrare:**   
 +Două numere întregi ''​a''​ și ''​b''​ — dimensiunile dreptunghiului.
  
-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.+**Date de ieșire:​** ​  
 +Se afișează un singur număr întreg — numărul minim de tăieturi necesare.
  
 +Problema se poate testa la:  ​
 +https://​cses.fi/​problemset/​task/​1744
  
-<spoiler Exemplu 1> +======= ​2) Removal Game =======
-$n 3$ +
-|i|1|2|3| +
-|v|2|6|4|+
  
-Răspuns$7$+**Enunt:**   
 +Se dă un șir de ''​n''​ numere întregi. Doi jucători joacă alternativ. La fiecare mutare, un jucător poate elimina primul sau ultimul element din șir și adaugă valoarea acelui element la scorul său.   
 +Ambii jucători joacă optim.  ​
  
-Explicație: Toate subșirurile posibile sunt +Determinati scorul maxim pe care îl poate obține primul jucător.
-  * $[2]$ +
-  * $[2, 6]$ +
-  * $[2, 6, 4]$ +
-  * $[2, 4]$ +
-  * $[6]$ +
-  * $[6, 4]$ +
-  * $[4]$ +
-Toate subșirurile de mai sus au suma pară. +
-</​spoiler>​+
  
 +**Date de intrare:​**  ​
 +Pe prima linie se află un număr întreg ''​n''​.  ​
 +Pe a doua linie se află ''​n''​ numere întregi reprezentând valorile din șir.
  
-<spoiler Exemplu 2> +**Date de ieșire:​**  ​ 
-$n = 3$ +Se afișează un singur număr întreg — scorul maxim al primului jucător.
-|i|1|2|3| +
-|v|2|1|3|+
  
-Răspuns$3$+Problema se poate testa la  
 +https://​cses.fi/​problemset/​task/​1097/​
  
-Explicație:​ Toate subșirurile posibile sunt +======= ​3) Array Description =======
-  * $[2]$ +
-  * $[2, 1]$ +
-  * $[2, 1, 3]$ +
-  * $[2, 3]$ +
-  * $[1]$ +
-  * $[1, 3]$ +
-  * $[3]$+
  
-Subșirurile cu sumă pară sunt: $[2]$$[2, 1, 3]$, $[1, 3]$.+**Enunt:​** ​  
 +Se dă un vector de lungime ''​n''​. Fiecare element este un număr între 1 și ''​m''​. Unele poziții ​sunt deja fixateiar altele au valoarea 0ceea ce înseamnă că pot fi alese liber. ​  
 +Un vector este valid dacă diferența absolută dintre două elemente consecutive este cel mult 1.  
  
-</​spoiler>​+Determinati câte vectori valizi pot fi formați respectând valorile deja fixate.
  
 +**Date de intrare:​**  ​
 +Pe prima linie se află două numere întregi ''​n''​ și ''​m''​.  ​
 +Pe a doua linie se află ''​n''​ numere întregi reprezentând vectorul inițial (valorile 0 indică poziții nefixate).
  
-<spoiler Exemplu 3> +**Date de ieșire:​**  ​ 
-$n = 3$ +Se afișează un singur număr întreg — numărul de vectori valizi modulo 10⁹+7.
-|i|1|2|3| +
-|v|3|2|1|+
  
-Răspuns$3$+Problema se poate testa la  
 +https://​cses.fi/​problemset/​task/​1746/​
  
-Explicație:​ Toate subșirurile posibile sunt +======= 4) Student Attendance Record II =======
-  * $[3]$ +
-  * $[3, 2]$ +
-  * $[3, 2, 1]$ +
-  * $[3, 1]$ +
-  * $[2]$ +
-  * $[2, 1]$ +
-  * $[1]$+
  
-Subșirurile cu sumă pară sunt$[3, 2, 1]$, $[3, 1]$, $[2]$.+**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  
 +    *  P (present) — prezent ​  
 +    * L (late) — întârziat ​  
 +    * A (absent) — absent  ​
  
-</​spoiler>​+Un istoric este considerat valid dacă: ​  
 +    * conține cel mult o absență (A)   
 +    * nu conține mai mult de două întârzieri consecutive (L)  ​
  
-<​note>​ +Determinati câte istorice de prezență valide de lungime ''​n'' ​există.
-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).+
  
-În problemele de numărat, există o **șansă** bună să putem găsi (și) o formulă matematică,​ ce poate fi implementată într-un mod mai eficient decât o recurență DP +**Date de intrare:**   
-</​note>​+Un număr întreg ''​n''​ — numărul de zile.
  
-<spoiler Hint> +**Date de ieșire:**   
-Câte subșiruri au suma **impară**? +Se afișează un singur număr întreg — numărul de istorice valide modulo 10⁹+7.
-</​spoiler>​+
  
-<​hidden>​ +Problema ​se poate testa la  
-<spoiler Soluție>​ +https://leetcode.com/problems/student-attendance-record-ii/description/
-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>​ +
-</hidden>+
  
-=== Expresie booleană ​=== +======= 5) Burst Balloons =======
-Se dă o expresie booleană corectă cu n termeni. Fiecare din termeni poate fi unul din stringurile **true**, **false**, **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**).+**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ă spargerebalonul dispareiar vecinii lui devin adiacenți. La extremități se consideră două baloane imaginare cu valoarea 1 
  
-Deoarece rezultatul poate fi prea mare, se cere **restul împărțirii** lui la $1000000007$ ($10^9 + 7$).+Determinati numărul maxim de monede pe care îl puteți obține spargând toate baloanele într-o anumită ordine.
  
-<​note>​ +**Date de intrare:**   
-În schelet vom codifica cu valori de tip char cele 5 stringuri:​ +Un vector de ''​n'' ​numere întregi care reprezintă valorile baloanelor.
-  * **false**: '​F'​ +
-  ​* **true**: '​T'​ +
-  * **and**: '&'​ +
-  * **or**: ​'|' +
-  * **xor**: ​'^'+
  
-Funcția pe care va trebui să o implementați voi va folosi variabilele ​**n** (numărul de termeni) și **expr** (vectorul cu termenii expresiei). +**Date de ieșire:**   
-</​note>​+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/​
  
-<​spoiler ​Exemplu 1+===== Extra (studiu de caz pentru acasă) ===== 
-$n = 5$ și $expr = ['​T',​ '&',​ '​F',​ '​^',​ '​T'​]$ (expr = [** true and false xor true**])+<​spoiler ​Por Costel si Azerath
 +Rezolvati pe infoarena problema ​[[https://​infoarena.ro/​problema/​azerah|Por Costel si Azerah]].
  
-Răspuns$2$ +HintCâte subșiruri au suma **impară**?
- +
-Explicație:​ Există 2 moduri corecte de a paranteza expresia astfel încât să obținem rezultatul ​**true** (1). +
-  ​$ T&(F^T) $ +
-  ​$ (T&F)^T $+
 </​spoiler>​ </​spoiler>​
  
-<​spoiler ​Hint+<​spoiler ​Parantezare booleană
-    ​Complexitate temporală dorită este $O(n ^ 3)$. +Rezolvati pe geeksforgeeks problema [[https://​www.geeksforgeeks.org/problems/​boolean-parenthesization5610/​1|Parantezare booleană]].
-     +
-    Opțional, se pot defini funcții ajutătoare precum **is_operand**,​ **is_operator**,​ **evaluate**. +
-</spoiler>+
  
-<note tip> +Hint: Complexitate temporală dorită este $O(n ^ 3)$. 
-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**.+   
 +Opțional, se pot defini funcții ajutătoare precum ​**is_operand**,​ **is_operator**,​ **evaluate**.
  
 +</​spoiler>​
  
-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 booleană** partiționăm **toate parantezările posibile după rezultatul lor** (câte dau true/​false). 
- 
-</​note>​ 
-===== Extra (studiu de caz pentru acasă) ===== 
 <spoiler Extratereștrii>​ <spoiler Extratereștrii>​
 Rezolvați 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
pa/laboratoare/laborator-02.1773092364.txt.gz · Last modified: 2026/03/09 23:39 by radu.nichita
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