This shows you the differences between two versions of the page.
pa:laboratoare:laborator-01 [2018/02/26 01:25] darius.neatu [Exercitii] |
pa:laboratoare:laborator-01 [2022/03/21 23:11] (current) radu.nichita [Exerciții] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laborator 01: Divide et Impera ====== | ====== Laborator 01: Divide et Impera ====== | ||
- | Responsabili: | ||
- | * [[visanr95@gmail.com|Radu Vișan]] | ||
- | * [[cristb@gmail.com|Cristian Banu]] | ||
- | * [[neatudarius@gmail.com|Darius Neațu]] | ||
===== Obiective laborator ===== | ===== Obiective laborator ===== | ||
- | * Înțelegerea conceptului teoretic din spatele descompunerii | + | * Înțelegerea conceptului teoretic din spatele descompunerii unei probleme |
* Rezolvarea de probleme abordabile folosind conceptul de Divide et Impera | * Rezolvarea de probleme abordabile folosind conceptul de Divide et Impera | ||
- | ===== Precizari initiale ===== | + | ===== Precizări inițiale ===== |
<note> | <note> | ||
- | Toate exemplele de cod se gasesc in {{pa:new_pa:demo-lab01.zip}}. | + | Toate exemplele de cod se găsesc pe pagina [[https://github.com/acs-pa/pa-lab/tree/main/demo/lab01|pa-lab::demo/lab01]]. |
- | Acestea apar incorporate si in textul laboratorului pentru a facilita parcurgerea cursiva a laboratorului. | + | 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 bucatile de cod prezentate in partea introductiva a laboratorului (inainte de exercitii) 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 sa 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. |
- | * Va rugam sa incercati si codul din arhiva ** demo-lab01.zip**, inainte de a raporta ca ceva nu merge. :D | + | * Vă rugam să compilați **DOAR** codul de pe GitHub. Pentru raportarea problemelor, contactați unul dintre maintaineri. |
- | * Pentru orice problema legata de continutul acestei pagini, va rugam sa dati email unuia dintre responsabili. | + | * Pentru orice problemă legată de conținutul acestei pagini, vă rugam să dați e-mail unuia dintre responsabili. |
===== Importanţă – aplicaţii practice ===== | ===== Importanţă – aplicaţii practice ===== | ||
Line 35: | Line 31: | ||
===== Prezentarea generală a problemei ===== | ===== Prezentarea generală a problemei ===== | ||
- | O descriere a tehnicii D&I: “Divide and Conquer algorithms break the problem into several sub-problems that are similar to the original problem but smaller in size, solve the sub-problems recursively, and then combine these solutions to create a solution to the original problem.” [7] | + | O descriere a tehnicii D&I: “Divide and Conquer algorithms break the problem into several sub-problems that are similar to the original problem but smaller in size, solve the sub-problems recursively, and then combine these solutions to create a solution to the original problem.” |
- | Deci un algoritm D&I **împarte problema** în mai multe subprobleme similare cu problema inițială şi de dimensiuni mai mici, **rezolva sub-problemele** recursiv şi apoi **combina soluțiile** obţinute pentru a obține soluția problemei inițiale. | + | Deci un algoritm D&I **împarte problema** în mai multe subprobleme similare cu problema inițială şi de dimensiuni mai mici, **rezolvă subproblemele** recursiv şi apoi **combină soluțiile** obţinute pentru a obține soluția problemei inițiale. |
Sunt trei pași pentru aplicarea algoritmului D&I: | Sunt trei pași pentru aplicarea algoritmului D&I: | ||
* **Divide**: împarte problema în una sau mai multe //probleme similare de dimensiuni mai mici//. | * **Divide**: împarte problema în una sau mai multe //probleme similare de dimensiuni mai mici//. | ||
- | * **Impera** (stăpânește): rezolva subprobleme recursiv; dacă dimensiunea sub-problemelor este mica se rezolva iterativ. | + | * **Impera** (stăpânește): rezolvă subproblemele recursiv; dacă dimensiunea sub-problemelor este mică, se rezolvă iterativ. |
- | * **Combină**: combină soluțiile sub-problemelor pentru a obține soluția problemei inițiale. | + | * **Combină**: combină soluțiile subproblemelor pentru a obține soluția problemei inițiale. |
Complexitatea algoritmilor D&I se calculează după formula: | Complexitatea algoritmilor D&I se calculează după formula: | ||
Line 49: | Line 45: | ||
$T(n) = D(n) + S(n) + C(n)$, | $T(n) = D(n) + S(n) + C(n)$, | ||
- | unde $D(n)$, $S(n)$ şi $C(n)$ reprezintă complexitățile celor 3 pași descriși mai sus: divide, stăpânește respectiv combină. | + | unde $D(n)$, $S(n)$ şi $C(n)$ reprezintă complexitățile celor 3 pași descriși mai sus: divide, stăpânește, respectiv combină. |
===== Probleme clasice ===== | ===== Probleme clasice ===== | ||
==== MergeSort ==== | ==== MergeSort ==== | ||
- | === Enunt === | + | === Enunț === |
Sortarea prin interclasare (MergeSort [[http://www.sorting-algorithms.com/merge-sort|[1]]]) este un algoritm de sortare de vectori ce folosește paradigma D&I: | Sortarea prin interclasare (MergeSort [[http://www.sorting-algorithms.com/merge-sort|[1]]]) este un algoritm de sortare de vectori ce folosește paradigma D&I: | ||
Line 62: | Line 58: | ||
=== Pseudocod === | === Pseudocod === | ||
- | Mai jos gasiti algoritmul MergeSort scris in pseudocod. | + | Mai jos găsiți algoritmul MergeSort scris în pseudocod. |
<spoiler Pseudocod> | <spoiler Pseudocod> | ||
Line 96: | Line 92: | ||
<spoiler Implementare in C++> | <spoiler Implementare in C++> | ||
- | Mai jos puteti gasi o implementare in C++. | + | Mai jos puteti găsi o implementare în C++. |
<code cpp> | <code cpp> | ||
Line 176: | Line 172: | ||
- | * **complexitate temporala** : $T=O(n * log(n))$ | + | * **complexitate temporală** : $T=O(n * log(n))$ |
- | * Ce inseamna aceasta metrica? Masoara efectiv **timpul de executie** al algoritmului (nu include citiri, afisari etc). | + | * Ce înseamnă această metrică? Măsoara efectiv **timpul de execuție** al algoritmului (nu include citiri, afișări etc). |
* **complexitate spatiala** : $S=O(n)$ | * **complexitate spatiala** : $S=O(n)$ | ||
- | * Ce inseamna aceasta metrica? Masoara efectiv **memoria suplimentara** folosita de algoritm (in acest caz ne referim strict la buffer-ul temporar). | + | * Ce înseamnă această metrica? Măsoara efectiv **memoria suplimentară** folosită de algoritm (în acest caz ne referim strict la buffer-ul temporar). |
<note> | <note> | ||
- | Retineti cele doua conventii despre complexitati de mai sus. Le vom folosi pentru restul semestrului. | + | Rețineți cele două convenții despre complexități de mai sus. Le vom folosi pentru restul semestrului. |
</note> | </note> | ||
==== Binary Search ==== | ==== Binary Search ==== | ||
- | === Enunt === | + | === Enunț === |
Se dă un **vector sortat crescător** ($v[1]$, $v[2]$, ..., $v[n]$) ce conține valori reale distincte și o valoare x. | Se dă un **vector sortat crescător** ($v[1]$, $v[2]$, ..., $v[n]$) ce conține valori reale distincte și o valoare x. | ||
- | Sa se găsească la ce **poziție** apare x în vectorul dat. | + | Să se găsească la ce **poziție** apare x în vectorul dat. |
=== Rezolvare === | === Rezolvare === | ||
- | BinarySearch (Cautare Binara), se rezolva cu un algoritm D&I: | + | BinarySearch (Căutare Binară), se rezolva cu un algoritm D&I: |
* **Divide**: împărțim vectorul în doi sub-vectori de dimensiune n/2. | * **Divide**: împărțim vectorul în doi sub-vectori de dimensiune n/2. | ||
Line 214: | Line 210: | ||
=== Complexitate === | === Complexitate === | ||
- | * **complexitate temporala** : $T = O(log (n))$ | + | * **complexitate temporală** : $T = O(log (n))$ |
- | * se deduce din recurenta $T(n)=T(n/2) + O(1)$ | + | * se deduce din recurența $T(n)=T(n/2) + O(1)$ |
- | * * **complexitate spatiala** : $S=O(1)$ | + | * **complexitate spațială** : $S=O(1)$ |
* nu avem structuri de date complexe auxiliare | * nu avem structuri de date complexe auxiliare | ||
- | * atragem atentia ca acest algoritm se poate implementa si **recursiv**, caz in care complexitatea spatiala devine $O(log(n))$, intrucat salvam pe stiva $O(log(n))$ parametri (intregi, referinte) | + | * atragem atenția că acest algoritm se poate implementa și **recursiv**, caz în care complexitatea spațiala devine $O(log(n))$, întrucât salvăm pe stivă $O(log(n))$ parametri (întregi, referințe) |
==== Turnurile din Hanoi ==== | ==== Turnurile din Hanoi ==== | ||
- | === Enunt === | + | === Enunț === |
- | Se considera 3 tije $S$ (**sursa**), $D$ (**destinatie**), $aux$ (**auxiliar**) şi n discuri de dimensiuni distincte ($1, 2, ..., n$ - ordinea crescătoare a dimensiunilor) situate inițial toate pe tija $S$ în ordinea $1,2,...,n$ (de la vârf către baza). | + | Se consideră 3 tije $S$ (**sursa**), $D$ (**destinatie**), $aux$ (**auxiliar**) şi n discuri de dimensiuni distincte ($1, 2, ..., n$ - ordinea crescătoare a dimensiunilor) situate inițial toate pe tija $S$ în ordinea $1,2,...,n$ (de la vârf către baza). |
Singura operație care se poate efectua este de a selecta un disc ce se află în vârful unei tije şi plasarea lui în vârful altei tije astfel încât să fie așezat deasupra unui disc de dimensiune mai mare decât a sa. | Singura operație care se poate efectua este de a selecta un disc ce se află în vârful unei tije şi plasarea lui în vârful altei tije astfel încât să fie așezat deasupra unui disc de dimensiune mai mare decât a sa. | ||
- | Sa se găsească un algoritm prin care se mută toate discurile de pe tija $S$ pe tija $D$ (problema turnurilor din Hanoi). | + | Să se găsească un algoritm prin care se mută toate discurile de pe tija $S$ pe tija $D$.(problema turnurilor din Hanoi). |
- | === Solutie === | + | === Soluție === |
Pentru rezolvarea problemei folosim următoarea strategie [[http://www.mathcs.org/java/programs/Hanoi/index.html|[9]]]: | Pentru rezolvarea problemei folosim următoarea strategie [[http://www.mathcs.org/java/programs/Hanoi/index.html|[9]]]: | ||
- | * mutam primele $n-1$ discuri de pe tija S pe tija aux folosindu-ne de tija D. | + | * mutăm primele $n-1$ discuri de pe tija S pe tija aux folosindu-ne de tija D. |
- | * mutam discul n pe tija D. | + | * mutăm discul n pe tija D. |
- | * mutam apoi cele $n-1$ discuri de pe tija aux pe tija D folosindu-ne de tija S. | + | * mutăm apoi cele $n-1$ discuri de pe tija aux pe tija D folosindu-ne de tija S. |
- | Ideea din spate este ca avem mereu o singura sursa si o singura destinatie sa atingem un scop. Intotdeauna a 3-a tija va fi considerata auxiliara si poate fi folosita pentru a atinge scopul propus. | + | Ideea din spate este că avem mereu o singura sursă si o singură destinație să atingem un scop. Întotdeauna a 3-a tija va fi considerată auxiliară și poate fi folosită pentru a atinge scopul propus. |
=== Algoritm === | === Algoritm === | ||
Line 255: | Line 251: | ||
=== Complexitate === | === Complexitate === | ||
- | * **complexitate temporala** : $T = O(2^n)$ | + | * **complexitate temporală** : $T(n) = O(2^n)$ |
- | * se deduce din recurenta $T(n)=2*T(n - 1) + O(1)$ | + | * se deduce din recurența $T(n)=2*T(n - 1) + O(1)$ |
- | * * **complexitate spatiala** : $S=O(n)$ | + | * **complexitate spațială** : $S(n) = O(n)$ |
* la un moment dat, nivelul maxim de recursivitate este n | * la un moment dat, nivelul maxim de recursivitate este n | ||
==== ZParcurgere ==== | ==== ZParcurgere ==== | ||
- | === Enunt === | + | === Enunț === |
- | Gigel are o tabla patratica de dimensiuni $2^n * 2^n$. Ar vrea sa scrie pe patratelele tablei numere naturale cuprinse intre $1$ si $2^n * 2^n$ conform unei parcurgeri mai deosebite pe care o numeste **Z-parcurgere**. | + | Gigel are o tablă pătratică de dimensiuni $2^n * 2^n$. Ar vrea să scrie pe pătrățelele tablei numere naturale cuprinse între $1$ si $2^n * 2^n$ conform unei parcurgeri mai deosebite pe care o numește **Z-parcurgere**. |
- | O Z-parcurgere viziteaza recursiv cele patru cadrane ale tablei in ordinea: **stanga-sus**, **dreapta-sus**, **stanga-jos**, **dreapta-jos**. | + | O Z-parcurgere vizitează recursiv cele patru cadrane ale tablei în ordinea: **stânga-sus**, **dreapta-sus**, **stânga-jos**, **dreapta-jos**. |
- | La un moment dat Gigel ar vrea sa stie ce **numar de ordine** trebuie sa scrie conform Z-parcurgerii pe anumite patratele date prin coordonatele lor $( x, y )$. Gigel incepe umplerea tablei **intotdeauna** din coltul din stanga-sus. | + | La un moment dat, Gigel ar vrea să știe ce **număr de ordine** trebuie să scrie conform Z-parcurgerii pe anumite pătrațele date prin coordonatele lor $( x, y )$. Gigel incepe umplerea tablei **întotdeauna** din colțul din stânga-sus. |
<spoiler Exemplu 1> | <spoiler Exemplu 1> | ||
$n = 1$ si $(x, y) = (2, 2)$ | $n = 1$ si $(x, y) = (2, 2)$ | ||
- | Raspuns: $4$ | + | Răspuns: $4$ |
- | Explicatie: Matricea arata ca in exemplul urmator. | + | Explicație: Matricea arată ca în exemplul următor. |
|1|2| | |1|2| | ||
|3|4| | |3|4| | ||
Line 283: | Line 279: | ||
$n = 2$ si $(x, y) = (3, 3)$ | $n = 2$ si $(x, y) = (3, 3)$ | ||
- | Raspuns: $13$ | + | Răspuns: $13$ |
- | Explicatie: Matricea arata ca in exemplul urmator. | + | Explicație: Matricea arată ca în exemplul următor. |
|1|2|5|6| | |1|2|5|6| | ||
|3|4|7|8| | |3|4|7|8| | ||
Line 292: | Line 288: | ||
</spoiler> | </spoiler> | ||
- | === Solutie === | + | === Soluție === |
- | Analizand modul in care se **completeaza** tabloul/matricea din enunt, observam ca la fiecare etapa impartim matricea (**problema**) in 4 submatrici (**4 subprobleme**). De asemenea, sirul de numere pe care dorim sa il punem in matrice se imparte in 4 secvente, fiecare corespunzand unei submatrici. | + | Analizând modul în care se **completează** tabloul/matricea din enunț, observăm că la fiecare etapa împărțim matricea (**problema**) în 4 submatrici (**4 subprobleme**). De asemenea, șirul de numere pe care dorim să il punem în matrice se împarte în 4 secvente, fiecare corespunzând unei submatrici. |
- | Observam astfel ca problema suporta **descompunerea** in **subprobleme disjuncte** si cu **structura similara**, ceea ce ne face sa ne gandim la o solutie cu Divide et Impera. | + | Observăm astfel că problema suportă **descompunerea** în **subprobleme disjuncte** și cu **structura similara**, ceea ce ne face să ne gândim la o soluție cu Divide et Impera. |
=== Complexitate === | === Complexitate === | ||
- | * **complexitate temporala** : $T = O(n)$ | + | * **complexitate temporală** : $T = O(n)$ |
* $\log_{4} (2^n) = \frac{1}{2} \log _{2} (2^n) = \frac{1}{2} n $ | * $\log_{4} (2^n) = \frac{1}{2} \log _{2} (2^n) = \frac{1}{2} n $ | ||
- | * * **complexitate spatiala** : $S=O(n)$ | + | * **complexitate spatială** : $S=O(n)$ |
- | * stocam parametri pentru recursivitate | + | * stocăm parametri pentru recursivitate |
- | * solutia se poate implementa si iterativ, caz in care $S = O(1)$; deoarece dimensinile spatiului de cautare sunt $2^n * 2^n$, n este foarte mic ($n <= 15$), de aceea o solutie iterativa nu aduce nici un castig **efectiv** in aceasta situatie | + | * solutia se poate implementa si iterativ, caz in care $S = O(1)$; deoarece dimensiunile spațiului de căutare sunt $2^n * 2^n$, n este foarte mic ($n <= 15$), de aceea o solutie iterativa nu aduce nici un câștig **efectiv** în această situație. |
===== Concluzii ===== | ===== Concluzii ===== | ||
- | Divide et impera este o tehnică folosită pentru a realiza solutii pentru o anumita clasa de probleme: acestea contin **subprobleme disjuncte** si cu **structura similara**. În cadrul acestei tehnici se disting trei etape: divide, stăpânește și combină. | + | Divide et impera este o tehnică folosită pentru a realiza soluții pentru o anumita clasă de probleme: acestea contin **subprobleme disjuncte** și cu **structură similară**. În cadrul acestei tehnici se disting trei etape: divide, stăpânește și combină. |
Mai multe exemple de algoritmi care folosesc tehnica divide et impera puteți găsi la [[http://www.cs.berkeley.edu/~vazirani/algorithms/chap2.pdf|[11]]]. | Mai multe exemple de algoritmi care folosesc tehnica divide et impera puteți găsi la [[http://www.cs.berkeley.edu/~vazirani/algorithms/chap2.pdf|[11]]]. | ||
- | ===== Exercitii ===== | + | ===== Exerciții ===== |
<note> | <note> | ||
- | In acest laborator vom folosi scheletul de laborator din arhiva {{pa:new_pa:skel-lab01.zip}}. | + | Scheletul de laborator se găsește pe pagina [[https://github.com/acs-pa/pa-lab/tree/main/skel/lab01|pa-lab::skel/lab01]]. |
</note> | </note> | ||
=== Count occurrences === | === Count occurrences === | ||
- | Se da un sir sortat **v** cu **n** elemente. Gasiti numarul de elemente egale cu **x** din sir. | + | Se dă un șir sortat **v** cu **n** elemente. Găsiți numărul de elemente egale cu **x** din șir. |
<spoiler Exemplu 1> | <spoiler Exemplu 1> | ||
Line 324: | Line 320: | ||
|v|1|2|4|10|10|20| | |v|1|2|4|10|10|20| | ||
- | Raspuns: $2$ | + | Răspuns: $2$ |
- | Explicatie: 10 apare de 2 ori in sir. | + | Explicație: 10 apare de 2 ori in sir. |
</spoiler> | </spoiler> | ||
Task-uri: | Task-uri: | ||
- | * Aceasta problema este deja rezolvata. Pentru a va acomoda cu scheletul, va trebui sa faceti cativa pasi: | + | * Aceasta problemă este deja rezolvată. Pentru a vă acomoda cu scheletul, va trebui sa faceți câțiva pași: |
- | * Rulati comanda $./check.sh$ si cititi cum se foloseste checker-ul. | + | * Rulați comanda $./check.sh$ si cititi cum se foloseste checker-ul. |
- | * Rulati comanda necesara pentru a rula task-ul 1. Sursa nu implementeaza corect algoritmul si returneaza valori default. Din acest motiv primiti mesajul **WRONG ANSWER**. | + | * Rulați comanda necesara pentru a rula task-ul 1. Sursa nu implementeaza corect algoritmul si returneaza valori default. Din acest motiv primiti mesajul **WRONG ANSWER**. |
- | * Copiati urmatoarea sursa in folderul corespunzator. Rulati comanda anterioara. Observati mesajele afisate cand ati rezolvat corect un task. | + | * Copiati următoarea sursă în folderul corespunzător. Rulați comanda anterioară. Observați mesajele afișate când ați rezolvat corect un task. |
<spoiler Solutie C++> | <spoiler Solutie C++> | ||
Sursa **main.cpp** asociata cu task 1 este mai jos. | Sursa **main.cpp** asociata cu task 1 este mai jos. | ||
Line 343: | Line 339: | ||
class Task { | class Task { | ||
public: | public: | ||
- | void solve() { | + | void solve() { |
- | read_input(); | + | read_input(); |
- | print_output(get_result()); | + | print_output(get_result()); |
- | } | + | } |
private: | private: | ||
- | void read_input() { | + | int n, x; |
- | ifstream fin("in"); | + | vector<int> v; |
- | fin >> n; | + | |
- | for (int i = 0, e; i < n; i++) { | + | |
- | fin >> e; | + | |
- | v.push_back(e); | + | |
- | } | + | |
- | fin >> x; | + | |
- | fin.close(); | + | |
- | } | + | |
- | int find_first() { | + | void read_input() { |
- | int left = 0, right = n - 1, mid, res = -1; | + | ifstream fin("in"); |
- | while (left <= right) { | + | fin >> n; |
- | mid = (left + right) / 2; | + | for (int i = 0, e; i < n; i++) { |
- | if (v[mid] >= x) { | + | fin >> e; |
- | res = mid; | + | v.push_back(e); |
- | right = mid - 1; | + | } |
- | } else { | + | fin >> x; |
- | left = mid + 1; | + | fin.close(); |
- | } | + | } |
- | } | + | |
- | return res; | + | |
- | } | + | |
- | int find_last() { | + | int find_first() { |
- | int left = 0, right = n - 1, mid, res = -1; | + | int left = 0, right = n - 1, mid, res = -1; |
- | while (left <= right) { | + | while (left <= right) { |
- | mid = (left + right) / 2; | + | mid = (left + right) / 2; |
- | if (v[mid] <= x) { | + | if (v[mid] >= x) { |
- | res = mid; | + | res = mid; |
- | left = mid + 1; | + | right = mid - 1; |
- | } else { | + | } else { |
- | right = mid - 1; | + | left = mid + 1; |
- | } | + | } |
- | } | + | } |
- | return res; | + | return (res != -1 && v[res] == x) ? res : -1; |
- | } | + | } |
- | int get_result() { | + | int find_last() { |
- | int first = find_first(); | + | int left = 0, right = n - 1, mid, res = -1; |
- | int last = find_last(); | + | while (left <= right) { |
- | if (first == -1 || last == -1) { | + | mid = (left + right) / 2; |
- | return 0; | + | if (v[mid] <= x) { |
- | } | + | res = mid; |
- | return last - first + 1; | + | left = mid + 1; |
- | } | + | } else { |
+ | right = mid - 1; | ||
+ | } | ||
+ | } | ||
+ | return (res != -1 && v[res] == x) ? res : -1; | ||
+ | } | ||
- | void print_output(int result) { | + | int get_result() { |
- | ofstream fout("out"); | + | int first = find_first(); |
- | fout << result; | + | int last = find_last(); |
- | fout.close(); | + | if (first == -1 || last == -1) { |
- | } | + | return 0; |
+ | } | ||
+ | return last - first + 1; | ||
+ | } | ||
- | int n, x; | + | void print_output(int result) { |
- | vector<int> v; | + | ofstream fout("out"); |
+ | fout << result; | ||
+ | fout.close(); | ||
+ | } | ||
}; | }; | ||
+ | // [ATENTIE] NU modifica functia main! | ||
int main() { | int main() { | ||
- | Task task; | + | // * se aloca un obiect Task pe heap |
- | task.solve(); | + | // (se presupune ca e prea mare pentru a fi alocat pe stiva) |
- | return 0; | + | // * se apeleaza metoda solve() |
+ | // (citire, rezolvare, printare) | ||
+ | // * se distruge obiectul si se elibereaza memoria | ||
+ | auto* task = new (std::nothrow) Task{}; // hint: cppreference/nothrow | ||
+ | if (!task) { | ||
+ | std::cerr << "new failed\n"; | ||
+ | return -1; | ||
+ | } | ||
+ | task->solve(); | ||
+ | delete task; | ||
+ | return 0; | ||
} | } | ||
</code> | </code> | ||
Line 468: | Line 475: | ||
} | } | ||
} | } | ||
- | return res; | + | return (res != -1 && v[res] == x) ? res : -1; |
} | } | ||
Line 482: | Line 489: | ||
} | } | ||
} | } | ||
- | return res; | + | return (res != -1 && v[res] == x) ? res : -1; |
} | } | ||
Line 508: | Line 515: | ||
</spoiler> | </spoiler> | ||
- | * Intelegeti solutia oferita impreuna cu asistentul vostru. | + | * Înțelegeți soluția oferită împreună cu asistentul vostru. |
- | * Care este complexitatea solutiei (timp + spatiu)? De ce? | + | * Care este complexitatea soluției (timp + spațiu)? De ce? |
=== SQRT === | === SQRT === | ||
- | Se da un numar real **n**. Scrieti un algoritm de complexitate **O(log n)** care sa calculeze $sqrt(n)$ cu o precizie de $0.001$. | + | Se dă un număr real **n**. Scrieți un algoritm de complexitate **O(log n)** care să calculeze $sqrt(n)$ cu o precizie de $0.001$. |
<spoiler Exemplu 1> | <spoiler Exemplu 1> | ||
$ n = 0.25 $ | $ n = 0.25 $ | ||
- | Raspuns: orice valoare intre $0.499$ si $0.501$ (inclusiv) | + | Răspuns: orice valoare intre $0.499$ si $0.501$ (inclusiv) |
</spoiler> | </spoiler> | ||
<note> | <note> | ||
- | Pentru a putea trece testele, trebuie sa afisati rezultatul cu **cel putin ** 4 zecimale. | + | Pentru a putea trece testele, trebuie sa afișați rezultatul cu **cel puțin ** 4 zecimale. |
</note> | </note> | ||
=== ZParcurgere === | === ZParcurgere === | ||
- | Rezolvati problema ZParcurgere folosind scheletul pus la dispozitie. Enuntul si explicatiile le gasiti in partea de seminar. | + | Rezolvați problema ZParcurgere folosind scheletul pus la dispoziție. Enunțul și explicațiile le găsiți în partea de seminar. |
- | === Exponentiere logaritmica === | + | === Exponențiere logaritmică === |
- | Se dau doua numere naturale **base** si **exponent**. Scrieti un algoritm de complexitate $O(log (exponent))$ care sa calculeze ${base} ^ {exponent} \ \% \ MOD $. | + | Se dau două numere naturale **base** și **exponent**. Scrieți un algoritm de complexitate $O(log (exponent))$ care să calculeze ${base} ^ {exponent} \ \% \ MOD $. |
<note> | <note> | ||
- | Intrucat expresia $ {base} ^ {exponent} $ este foarte mare, dorim sa aflam doar **restul** impartirii lui la un numar **MOD**. | + | Întrucât expresia $ {base} ^ {exponent} $ este foarte mare, dorim să aflăm doar **restul** împărțirii lui la un număr **MOD**. |
- | Proprietati matematice necesare: | + | Proprietăți matematice necesare: |
* $(a + b) \ \% \ MOD = ((a \ \% \ MOD) + (b \ \% \ MOD)) \ \% \ MOD $ | * $(a + b) \ \% \ MOD = ((a \ \% \ MOD) + (b \ \% \ MOD)) \ \% \ MOD $ | ||
* $(a \ * b) \ \% \ MOD = ((a \ \% \ MOD) \ * (b \ \% \ MOD)) \ \% \ MOD $ | * $(a \ * b) \ \% \ MOD = ((a \ \% \ MOD) \ * (b \ \% \ MOD)) \ \% \ MOD $ | ||
| | ||
- | Atentie la inmultire! Rezultatul **temporar** poate provoca un overflow. | + | Atenție la înmulțire! Rezultatul **temporar** poate provoca un overflow. |
- | Solutii: | + | |
+ | Soluții: | ||
* **C++**: $a * b$ => $1LL * a * b$ | * **C++**: $a * b$ => $1LL * a * b$ | ||
* **Java**: $a * b$ => $1L * a * b$ | * **Java**: $a * b$ => $1L * a * b$ | ||
Line 549: | Line 557: | ||
$ base = 2 $, $ exponent = 10$, $MOD = 5$ | $ base = 2 $, $ exponent = 10$, $MOD = 5$ | ||
- | Raspuns: $4$ | + | Răspuns: $4$ |
Explicatie: $2^{10} \ \% \ 5 = 4$ | Explicatie: $2^{10} \ \% \ 5 = 4$ | ||
Line 565: | Line 573: | ||
<note> | <note> | ||
- | Aceasta problema nu are schelet. | + | Aceasta problema nu are schelet, dar poate fi testată pe infoarena, la problema [[https://www.infoarena.ro/problema/inv | Inv]]. |
</note> | </note> | ||
</spoiler> | </spoiler> | ||
+ | <spoiler ClassicTask> | ||
+ | Testați soluția voastră de la **Exponentiere logaritmica** pe infoarena, la problema [[https://infoarena.ro/problema/classictask | ClassicTask ]] (trebuie să modificați numele fișierelor). | ||
+ | |||
+ | Identificați problema și modificați sursa astfel încât să luați punctaj maxim. | ||
+ | </spoiler> | ||
==== Extra ==== | ==== Extra ==== | ||
<spoiler Statistici de ordine> | <spoiler Statistici de ordine> | ||
Line 596: | Line 609: | ||
<spoiler Fractal> | <spoiler Fractal> | ||
- | Puteti rezolva aceasta problema pe [[https://infoarena.ro/problema/fractal| infoarena]]. | + | Puteți rezolva această problemă pe [[https://infoarena.ro/problema/fractal| infoarena]]. |
</spoiler> | </spoiler> | ||
- | + | <spoiler Hanoi> | |
- | <spoiler SSM> | + | Puteți rezolva această problemă pe [[https://www.infoarena.ro/problema/hanoi| infoarena]]. |
- | Puteti rezolva aceasta problema de [[https://ocw.cs.pub.ro/courses/pa/laboratoare/laborator-03#ssm | + | |
- | | aici]]. | + | |
- | + | ||
- | <note> | + | |
- | Pentru problema SSM vom studia o solutie potrivita in lab03. Puteti sa incercati sa o rezolvati cu Divide et Impera pentru a exersa cele invatate astazi. | + | |
- | </note> | + | |
</spoiler> | </spoiler> | ||
Line 612: | Line 619: | ||
Dându-se N numere întregi sub forma unei secvenţe de numere strict crescătoare, care se continuă cu o secvenţă de întregi strict descrescătoare, se doreşte determinarea punctului din întregul şir înaintea căruia toate elementele sunt strict crescătoare, şi dupa care, toate elementele sunt strict descrescătoare. Considerăm evident faptul că acest punct nu există dacă cele N numere sunt dispuse într-un şir fie doar strict crescător, fie doar strict descrescător. | Dându-se N numere întregi sub forma unei secvenţe de numere strict crescătoare, care se continuă cu o secvenţă de întregi strict descrescătoare, se doreşte determinarea punctului din întregul şir înaintea căruia toate elementele sunt strict crescătoare, şi dupa care, toate elementele sunt strict descrescătoare. Considerăm evident faptul că acest punct nu există dacă cele N numere sunt dispuse într-un şir fie doar strict crescător, fie doar strict descrescător. | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler K closest points to origin> | ||
+ | Puteți rezolva această problemă pe [[https://leetcode.com/problems/k-closest-points-to-origin/ | leetcode]] | ||
+ | </spoiler> | ||
+ | |||
+ | <spoiler Merge k Sorted Lists> | ||
+ | Puteți rezolva această problemă pe [[https://leetcode.com/problems/merge-k-sorted-lists/ | leetcode]] | ||
</spoiler> | </spoiler> | ||
+ | ===== Referințe ===== | ||
+ | [0] Chapter **Divide-and-Conquer**, "Introduction to Algorithms", Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein | ||