Differences

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

Link to this comparison view

pa:laboratoare:laborator-04 [2026/03/27 01:57]
radu.nichita
pa:laboratoare:laborator-04 [2026/03/27 02:05] (current)
radu.nichita
Line 1: Line 1:
 ====== Laborator 04: Backtracking ====== ====== Laborator 04: Backtracking ======
- + 
 ===== Obiective laborator ===== ===== Obiective laborator =====
-  * Întelegerea noțiunilor de bază despre backtracking;​ +  ​* Întelegerea noțiunilor de bază despre backtracking;​ 
-  * Însușirea abilităților de implementare a algoritmilor bazați pe backtracking;​ +  * Însușirea abilităților de implementare a algoritmilor bazați pe backtracking;​ 
-  * Rezolvarea unor probleme NP-complete în timp exponențial.+  * Rezolvarea unor probleme NP-complete în timp exponențial.
  
 ===== 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/lab05|pa-lab::demo/lab05]].+Toate exemplele de cod se găsesc pe pagina [[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​algorithms/lab04|pa-lab::algorithms/lab04]].
  
 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ă rugam să compilați **DOAR** codul de pe GitHub. Pentru raportarea problemelor,​ contactați unul dintre maintaineri.  +  * Vă rugam 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ă rugăm să dați e-mail unuia dintre responsabili.+  * Pentru orice problemă legată de conținutul acestei pagini, vă rugăm să dați e-mail unuia dintre responsabili.
  
  
Line 24: Line 24:
  
 ===== Importanța – aplicaţii practice ===== ===== Importanța – aplicaţii practice =====
-Există foarte multe probleme (de exemplu, problemele NP-complete sau NP-dificile) care pot fi rezolvate prin algoritmi de tip backtracking mai eficient decât prin „forta bruta” (adică generarea tuturor alternativelor și selectarea soluțiilor). Atenție însă, complexitatea computațională este de cele mai multe ori **exponențială**. O eficientizare se poate face prin combinarea cu tehnici de propagare a restricțiilor. Orice problemă care are nevoie de parcurgerea spațiului de stări se poate rezolva cu backtracking. +Există foarte multe probleme (de exemplu, problemele NP-complete sau NP-dificile) care pot fi rezolvate prin algoritmi de tip backtracking mai eficient decât prin „forta bruta” (adică generarea tuturor alternativelor și selectarea soluțiilor). Atenție însă, complexitatea computațională este de cele mai multe ori **exponențială**. O eficientizare se poate face prin combinarea cu tehnici de propagare a restricțiilor. Orice problemă care are nevoie de parcurgerea spațiului de stări se poate rezolva cu backtracking. ​
  
 ===== Descrierea problemei și a rezolvărilor ===== ===== Descrierea problemei și a rezolvărilor =====
Line 34: Line 34:
 Solution - solutia curenta pe care o extindem catre cea finala */ Solution - solutia curenta pe care o extindem catre cea finala */
 back(Domain,​ Solution): back(Domain,​ Solution):
-    if check(Solution):​ +    ​if check(Solution):​ 
-        print(Solution) +        print(Solution) 
-        return+        return
  
-    for value in Domain: +    ​for value in Domain: 
-        NextSolution = Solution.push(value) +        NextSolution = Solution.push(value) 
-        NextDomain = Domain.erase(value) +        NextDomain = Domain.erase(value) 
-        back(NextDomain,​ NextSolution)+        back(NextDomain,​ NextSolution)
 </​code>​ </​code>​
  
Line 51: Line 51:
 Solution - solutia curenta pe care o extindem catre cea finala */ Solution - solutia curenta pe care o extindem catre cea finala */
 back(Domain,​ Solution): back(Domain,​ Solution):
-    if check(Solution):​ +    ​if check(Solution):​ 
-        print(Solution) +        print(Solution) 
-        return+        return
  
-    for value in Domain: +    ​for value in Domain: 
-        /* DO */ +        /* DO */ 
-        Solution = Solution.push(value) +        Solution = Solution.push(value) 
-        Domain = Domain.erase(value) +        Domain = Domain.erase(value) 
-         +         
-        /* RECURSION */ +        /* RECURSION */ 
-        back(Domain,​ Solution) +        back(Domain,​ Solution) 
-         +         
-        /* UNDO */ +        /* UNDO */ 
-        Solution = Solution.pop() +        Solution = Solution.pop() 
-        Domain = Domain.insert(value)+        Domain = Domain.insert(value)
 </​code>​ </​code>​
  
Line 72: Line 72:
 ===== Exemple clasice ===== ===== Exemple clasice =====
 Ne vom ocupa în continuare de următoarele probleme: Ne vom ocupa în continuare de următoarele probleme:
-  * Permutări +    ​* Permutări 
-  * Combinări +    * Combinări 
-  * Aranjamente +    * Aranjamente 
-  * Submulțimi +    * Submulțimi 
-  * Generare de șiruri +    * Generare de șiruri 
-  * Problema damelor +    * Problema damelor 
-  * Problema șoricelului +    * Problema șoricelului 
-  * Tic-Tac-Toe +    * Tic-Tac-Toe 
-  * Sudoku +    * Sudoku 
-  * Ultimate Tic-Tac-Toe+    * Ultimate Tic-Tac-Toe
  
 <​note>​ <​note>​
Line 100: Line 100:
  
 Solutie: Solutie:
-  * {1, 2, 3} +  ​* {1, 2, 3} 
-  * {1, 3, 2} +  * {1, 3, 2} 
-  * {2, 1, 3} +  * {2, 1, 3} 
-  * {2, 3, 1} +  * {2, 3, 1} 
-  * {3, 1, 2} +  * {3, 1, 2} 
-  * {3, 2, 1}+  * {3, 2, 1}
  
 </​spoiler>​ </​spoiler>​
Line 118: Line 118:
 sa nu contina duplicate. Astfel, atunci cand domeniul ajunge vid, soluția este intotdeauna corecta */ sa nu contina duplicate. Astfel, atunci cand domeniul ajunge vid, soluția este intotdeauna corecta */
 bool check(std::​vector<​int>​ solution) { bool check(std::​vector<​int>​ solution) {
-    return true;+    ​return true;
 } }
  
 void printSolution(std::​vector<​int>​ solution) { void printSolution(std::​vector<​int>​ solution) {
-    for (auto &s : solution) { +    ​for (auto &s : solution) { 
-        std::cout << s << " "; +        std::cout << s << " "; 
-  ​  ​+    
-  ​  ​std::cout << "​\n";​+    std::cout << "​\n";​
 } }
  
 void back(std::​vector<​int>​ domain, std::​vector<​int>​ solution) { void back(std::​vector<​int>​ domain, std::​vector<​int>​ solution) {
-    /* dupa ce am folosit toate elementele din domeniu putem verifica daca +    ​/* dupa ce am folosit toate elementele din domeniu putem verifica daca 
-  ​  ​am gasit o solutie */ +    am gasit o solutie */ 
-  ​  ​if (domain.size() == 0) { +    if (domain.size() == 0) { 
-        if(check(solution)) { +        if(check(solution)) { 
-            printSolution(solution);​ +            printSolution(solution);​ 
-        +        
-        return; +        return; 
-  ​  ​}+    }
  
-    /* incercam sa adaugam in solutie toate valorile din domeniu, pe rand */ +    ​/* incercam sa adaugam in solutie toate valorile din domeniu, pe rand */ 
-  ​  ​for (unsigned int i = 0; i < domain.size();​ ++i) { +    for (unsigned int i = 0; i < domain.size();​ ++i) { 
-        /* cream o solutie noua si un domeniu nou care sunt identice cu cele +        /* cream o solutie noua si un domeniu nou care sunt identice cu cele 
-        de la pasul curent */ +        de la pasul curent */ 
-        std::​vector<​int>​ newSolution(solution),​ newDomain(domain);​+        std::​vector<​int>​ newSolution(solution),​ newDomain(domain);​
  
-        /* adaugam in noua solutie elementul ales din domeniu */ +        ​/* adaugam in noua solutie elementul ales din domeniu */ 
-        newSolution.push_back(domain[i]);​ +        newSolution.push_back(domain[i]);​ 
-        /* stergem elementul ales din noul domeniu */ +        /* stergem elementul ales din noul domeniu */ 
-        newDomain.erase(newDomain.begin() + i);+        newDomain.erase(newDomain.begin() + i);
  
-        /* apelam recursiv backtracking pe noul domeniu si noua solutie */ +        ​/* apelam recursiv backtracking pe noul domeniu si noua solutie */ 
-        back(newDomain,​ newSolution);​ +        back(newDomain,​ newSolution);​ 
-  ​  ​}+    }
 } }
  
 int main() { int main() {
-    /* dupa ce am citit n initializam domeniul cu n elemente, numerele de la 1 la n, +    ​/* dupa ce am citit n initializam domeniul cu n elemente, numerele de la 1 la n, 
-  ​  ​iar solutia este vida initial */ +    iar solutia este vida initial */ 
-  ​  ​std::​vector<​int>​ domain(n), solution; +    std::​vector<​int>​ domain(n), solution; 
-  ​  ​for (int i = 0; i < n; ++i) { +    for (int i = 0; i < n; ++i) { 
-        domain[i] = i + 1; +        domain[i] = i + 1; 
-  ​  ​}+    }
  
-    /* apelam backtracking pe domeniul nostru, cautand solutia in vectorul solution */ +    ​/* apelam backtracking pe domeniul nostru, cautand solutia in vectorul solution */ 
-  ​  ​back(domain,​ solution);+    back(domain,​ solution);
 } }
 </​code>​ </​code>​
Line 179: Line 179:
 Soluția va avea următoarele complexitati:​ Soluția va avea următoarele complexitati:​
  
-  * complexitate temporala : $T(n)=O(n * n!)$ +    ​* complexitate temporala : $T(n)=O(n * n!)$ 
-     * explicație : Complexitatea generarii permutarilor,​ $O(n!)$, se înmultește cu complexitatea copierii vectorilor soluție si domeniu si a stergerii elementelor din domeniu, $O(n)$ +        * explicație : Complexitatea generarii permutarilor,​ $O(n!)$, se înmultește cu complexitatea copierii vectorilor soluție si domeniu si a stergerii elementelor din domeniu, $O(n)$ 
-  * complexitate spatiala : $S(n)=O(n^2)$ +    * complexitate spatiala : $S(n)=O(n^2)$ 
-     * explicație : Fiecare nivel de recursivitate are propria lui copie a soluției și a domeniului. Sunt n nivele de recursivitate,​ deci complexitatea spatială este $O(n * n) = O(n^2)$+        * explicație : Fiecare nivel de recursivitate are propria lui copie a soluției și a domeniului. Sunt n nivele de recursivitate,​ deci complexitatea spatială este $O(n * n) = O(n^2)$
  
  
Line 192: Line 192:
 /* deoarece numerele sunt sterse din domeniu odata ce sunt folosite, soluția generata este garantata sa nu contina duplicate. Astfel, atunci cand domeniul ajunge vid, soluția este intotdeauna corecta */ /* deoarece numerele sunt sterse din domeniu odata ce sunt folosite, soluția generata este garantata sa nu contina duplicate. Astfel, atunci cand domeniul ajunge vid, soluția este intotdeauna corecta */
 bool check(std::​vector<​int>​ solution) { bool check(std::​vector<​int>​ solution) {
-    return true;+    ​return true;
 } }
  
 void printSolution(std::​vector<​int>​ &​solution) { void printSolution(std::​vector<​int>​ &​solution) {
-    for (int s : solution) { +    ​for (int s : solution) { 
-        std::cout << s << " "; +        std::cout << s << " "; 
-  ​  ​+    
-  ​  ​std::cout << "​\n";​+    std::cout << "​\n";​
 } }
  
 void back(std::​vector<​int>​ &​domain,​ std::​vector<​int>​ &​solution) { void back(std::​vector<​int>​ &​domain,​ std::​vector<​int>​ &​solution) {
-    /* dupa ce am folosit toate elementele din domeniu putem verifica daca +    ​/* dupa ce am folosit toate elementele din domeniu putem verifica daca 
-  ​  ​am gasit o solutie */ +    am gasit o solutie */ 
-  ​  ​if (domain.size() == 0) { +    if (domain.size() == 0) { 
-        if(check(solution)) { +        if(check(solution)) { 
-            printSolution(solution);​ +            printSolution(solution);​ 
-        +        
-        return; +        return; 
-  ​  ​}+    }
  
-    /* incercam sa adaugam in solutie toate valorile din domeniu, pe rand */ +    ​/* incercam sa adaugam in solutie toate valorile din domeniu, pe rand */ 
-  ​  ​for (unsigned int i = 0; i < domain.size();​ ++i) { +    for (unsigned int i = 0; i < domain.size();​ ++i) { 
-        /* retinem valoarea pe care o scoatem din domeniu ca sa o readaugam dupa +        /* retinem valoarea pe care o scoatem din domeniu ca sa o readaugam dupa 
-        apelarea recursiva a backtracking-ului */ +        apelarea recursiva a backtracking-ului */ 
-        int tmp = domain[i];+        int tmp = domain[i];
  
-        /* adaug elementul curent la potentiala solutie */ +        ​/* adaug elementul curent la potentiala solutie */ 
-        solution.push_back(domain[i]);​ +        solution.push_back(domain[i]);​ 
-        /* sterg elementul curent din domeniu ca sa il pot pasa prin referinta +        /* sterg elementul curent din domeniu ca sa il pot pasa prin referinta 
-        si sa nu fie nevoie sa creez alt domeniu */ +        si sa nu fie nevoie sa creez alt domeniu */ 
-        domain.erase(domain.begin() + i);+        domain.erase(domain.begin() + i);
  
-        /* apelez recursiv backtracking pe domeniul si solutia modificate */ +        ​/* apelez recursiv backtracking pe domeniul si solutia modificate */ 
-        back(domain,​ solution);+        back(domain,​ solution);
  
-        /* refac domeniul si solutia la modul in care aratau inainte de apelarea +        ​/* refac domeniul si solutia la modul in care aratau inainte de apelarea 
-        recursiva a backtracking-ului,​ adica readaug elementul eliminat in +        recursiva a backtracking-ului,​ adica readaug elementul eliminat in 
-        domeniu si il sterg din solutie */ +        domeniu si il sterg din solutie */ 
-        domain.insert(domain.begin() + i, tmp); +        domain.insert(domain.begin() + i, tmp); 
-        solution.pop_back();​ +        solution.pop_back();​ 
-  ​  ​}+    }
 } }
  
 int main() { int main() {
-    /* dupa ce am citit n initializam domeniul cu n elemente, numerele de la 1 la n, +    ​/* dupa ce am citit n initializam domeniul cu n elemente, numerele de la 1 la n, 
-  ​  ​iar solutia este vida initial */ +    iar solutia este vida initial */ 
-  ​  ​std::​vector<​int>​ domain(n), solution; +    std::​vector<​int>​ domain(n), solution; 
-  ​  ​for (int i = 0; i < n; ++i) { +    for (int i = 0; i < n; ++i) { 
-        domain[i] = i + 1; +        domain[i] = i + 1; 
-  ​  ​}+    }
  
-    /* apelam backtracking pe domeniul nostru, cautand solutia in vectorul solution */ +    ​/* apelam backtracking pe domeniul nostru, cautand solutia in vectorul solution */ 
-  ​  ​back(domain,​ solution);+    back(domain,​ solution);
 } }
 </​code>​ </​code>​
Line 256: Line 256:
 Soluția va avea următoarele complexități:​ Soluția va avea următoarele complexități:​
  
-  * complexitate temporală : $T(n)=O(n * n!)$ +  ​* complexitate temporală : $T(n)=O(n * n!)$ 
-  ​  ​* explicație : Complexitatea generării permutărilor,​ $O(n!)$, se înmulțește cu complexitatea ștergerii elementelor din domeniu, $O(n)$ +    * explicație : Complexitatea generării permutărilor,​ $O(n!)$, se înmulțește cu complexitatea ștergerii elementelor din domeniu, $O(n)$ 
-  * complexitate spatială : $S(n)=O(n)$ +  * complexitate spatială : $S(n)=O(n)$ 
-  ​  ​* explicație : Spre deosebire de solutia anterioară,​ toate nivelele de recursivitate folosesc aceeași soluție și același domeniu. Complexitatea spatială este astfel redusă la $O(n)$+    * explicație : Spre deosebire de solutia anterioară,​ toate nivelele de recursivitate folosesc aceeași soluție și același domeniu. Complexitatea spatială este astfel redusă la $O(n)$
 <​note>​ <​note>​
  
Line 273: Line 273:
  
 bool check(std::​vector<​int>​ &​solution) { bool check(std::​vector<​int>​ &​solution) {
-    return true;+    ​return true;
 } }
  
 void printSolution(std::​vector<​int>​ &​solution) { void printSolution(std::​vector<​int>​ &​solution) {
-    for (auto s : solution) { +    ​for (auto s : solution) { 
-        std::cout << s << " "; +        std::cout << s << " "; 
-  ​  ​+    
-  ​  ​std::cout << "​\n";​+    std::cout << "​\n";​
 } }
  
 void back(int step, int stop, std::​vector<​int>​ &​domain,​ void back(int step, int stop, std::​vector<​int>​ &​domain,​
-        std::​vector<​int>​ &​solution,​ std::​unordered_set<​int>​ &​visited) { +        ​std::​vector<​int>​ &​solution,​ std::​unordered_set<​int>​ &​visited) { 
-     +     
-  ​  ​/* vom verifica o solutie atunci cand am adaugat deja N elemente in solutie, +    /* vom verifica o solutie atunci cand am adaugat deja N elemente in solutie, 
-  ​  ​adica step == stop */ +    adica step == stop */ 
-  ​  ​if (step == stop) { +    if (step == stop) { 
-        /* deoarece am avut grija sa nu se adauge duplicate, "​check()"​ va returna +        /* deoarece am avut grija sa nu se adauge duplicate, "​check()"​ va returna 
-        intotdeauna "​true"​ */ +        intotdeauna "​true"​ */ 
-        if(check(solution)) { +        if(check(solution)) { 
-            printSolution(solution);​ +            printSolution(solution);​ 
-        +        
-        return; +        return; 
-  ​  ​}+    }
  
-    /* Adaugam in solutie fiecare element din domeniu care *NU* a fost vizitat +    ​/* Adaugam in solutie fiecare element din domeniu care *NU* a fost vizitat 
-  ​  ​deja renuntand astfel la nevoia de a verifica duplicatele la final prin +    deja renuntand astfel la nevoia de a verifica duplicatele la final prin 
-  ​  ​functia "​check()"​ */ +    functia "​check()"​ */ 
-  ​  ​for (unsigned int i = 0; i < domain.size();​ ++i) { +    for (unsigned int i = 0; i < domain.size();​ ++i) { 
-        /* folosim elementul doar daca nu e vizitat inca */ +        /* folosim elementul doar daca nu e vizitat inca */ 
-        if (visited.find(domain[i]) == visited.end()) { +        if (visited.find(domain[i]) == visited.end()) { 
-            /* il marcam ca vizitat si taiem eventuale expansiuni nefolositoare +            /* il marcam ca vizitat si taiem eventuale expansiuni nefolositoare 
-            viitoare (ex: daca il adaug in solutie pe 3 nu voi mai avea +            viitoare (ex: daca il adaug in solutie pe 3 nu voi mai avea 
-            niciodata nevoie sa il mai adaug pe 3 in continuare) */ +            niciodata nevoie sa il mai adaug pe 3 in continuare) */ 
-            visited.insert(domain[i]);​+            visited.insert(domain[i]);​
  
-            /* adaugam elementul curent in solutie pe pozitia pasului curent +            ​/* adaugam elementul curent in solutie pe pozitia pasului curent 
-            (step) */ +            (step) */ 
-            solution[step] = domain[i];+            solution[step] = domain[i];
  
-            /* apelam recursiv backtracking pentru pasul urmator */ +            ​/* apelam recursiv backtracking pentru pasul urmator */ 
-            back(step + 1, stop, domain, solution, visited);+            back(step + 1, stop, domain, solution, visited);
  
-            /* stergem vizitarea elementului curent (ex: pentru N = 3, dupa ce +            ​/* stergem vizitarea elementului curent (ex: pentru N = 3, dupa ce 
-            la pasul "step = 0" l-am pus pe 1 pe prima pozitie in solutie si +            la pasul "step = 0" l-am pus pe 1 pe prima pozitie in solutie si 
-            am continuat recursiv pana am ajuns la solutiile {1, 2, 3} si  +            am continuat recursiv pana am ajuns la solutiile {1, 2, 3} si  
-            {1, 3, 2}, ne dorim sa il punem pe 2 pe prima pozitie in solutie si +            {1, 3, 2}, ne dorim sa il punem pe 2 pe prima pozitie in solutie si 
-            sa continuam recursiv pentru a ajunge la solutiile {2, 1, 3} etc.) */ +            sa continuam recursiv pentru a ajunge la solutiile {2, 1, 3} etc.) */ 
-            visited.erase(domain[i]);​ +            visited.erase(domain[i]);​ 
-        +        
-  ​  ​}+    }
 } }
  
 int main() { int main() {
-    /* dupa ce am citit n initializam domeniul cu n elemente, numerele de la 1 la n, +    ​/* dupa ce am citit n initializam domeniul cu n elemente, numerele de la 1 la n, 
-  ​  ​iar solutia este initializata cu un vector de n elemente (deoarece o permutare +    iar solutia este initializata cu un vector de n elemente (deoarece o permutare 
-  ​  ​contine n elemente) */ +    contine n elemente) */ 
-  ​  ​std::​vector<​int>​ domain(n), solution(n);​ +    std::​vector<​int>​ domain(n), solution(n);​ 
-  ​  ​std::​unordered_set<​int>​ visited; +    std::​unordered_set<​int>​ visited; 
-  ​  ​for (int i = 0; i < n; ++i) { +    for (int i = 0; i < n; ++i) { 
-        domain[i] = i + 1; +        domain[i] = i + 1; 
-  ​  ​}+    }
  
-    /* apelam back cu step = 0 (atatea elemente avem adaugate in solutie), +    ​/* apelam back cu step = 0 (atatea elemente avem adaugate in solutie), 
-  ​  ​stop = n (stim ca vrem sa adaugam n elemente in solutie pentru ca o +    stop = n (stim ca vrem sa adaugam n elemente in solutie pentru ca o 
-  ​  ​permutare e alcatuita din n elemente), domain este vectorul de valori +    permutare e alcatuita din n elemente), domain este vectorul de valori 
-  ​  ​posibile, solution este vectorul care simuleaza stiva pe care o vom +    posibile, solution este vectorul care simuleaza stiva pe care o vom 
-  ​  ​umple, visited este un unordered_set (initial gol) in care retinem daca +    umple, visited este un unordered_set (initial gol) in care retinem daca 
-  ​  ​un element din domeniu se afla deja in solutia curenta la un anumit pas */ +    un element din domeniu se afla deja in solutia curenta la un anumit pas */ 
-  ​  ​back(0, n, domain, solution, visited);+    back(0, n, domain, solution, visited);
 } }
 </​code>​ </​code>​
Line 353: Line 353:
 Soluția va avea următoarele complexitați:​ Soluția va avea următoarele complexitați:​
  
-  * complexitate temporală : $T(n)=O(n * n!)$ +  ​* complexitate temporală : $T(n)=O(n * n!)$ 
-  ​  ​* explicație : Complexitatea generării permutărilor,​ O(n!), se înmulțește cu complexitatea iterării prin domeniu, $O(n)$ +    * explicație : Complexitatea generării permutărilor,​ O(n!), se înmulțește cu complexitatea iterării prin domeniu, $O(n)$ 
-  * complexitate spatială : $S(n)=O(n)$ +  * complexitate spatială : $S(n)=O(n)$ 
-  ​  ​* explicație : Toate nivelele de recursivitate folosesc aceeași soluție și același domeniu.+    * explicație : Toate nivelele de recursivitate folosesc aceeași soluție și același domeniu.
  
 <​note>​ <​note>​
Line 379: Line 379:
  
 Soluție: Soluție:
-  * {1, 2} +  ​* {1, 2} 
-  * {1, 3} +  * {1, 3} 
-  * {1, 4} +  * {1, 4} 
-  * {2, 3} +  * {2, 3} 
-  * {2, 4} +  * {2, 4} 
-  * {3, 4}+  * {3, 4}
  
 </​spoiler>​ </​spoiler>​
Line 395: Line 395:
  
 bool check(std::​vector<​int>​ &​solution) { bool check(std::​vector<​int>​ &​solution) {
-    return true;+    ​return true;
 } }
  
 void printSolution(std::​vector<​int>​ &​solution,​ std::​vector<​int>​ &​domain,​ int stop) { void printSolution(std::​vector<​int>​ &​solution,​ std::​vector<​int>​ &​domain,​ int stop) {
-    for (unsigned i = 0; i < stop; ++i) { +    ​for (unsigned i = 0; i < stop; ++i) { 
-        std::cout << domain[solution[i]] << " "; +        std::cout << domain[solution[i]] << " "; 
-  ​  ​+    
-  ​  ​std::cout << "​\n";​+    std::cout << "​\n";​
 } }
  
 void back(int step, int stop, std::​vector<​int>​ &​domain,​ void back(int step, int stop, std::​vector<​int>​ &​domain,​
-        std::​vector<​int>​ &​solution) { +        ​std::​vector<​int>​ &​solution) { 
-  ​  ​/* vom verifica o solutie atunci cand am adaugat deja K elemente in solutie, +    /* vom verifica o solutie atunci cand am adaugat deja K elemente in solutie, 
-  ​  ​adica step == stop */ +    adica step == stop */ 
-  ​  ​if (step == stop) { +    if (step == stop) { 
-        /* deoarece am avut grija sa se adauge elementele doar in ordine +        /* deoarece am avut grija sa se adauge elementele doar in ordine 
-        crescatoare,​ "​check()"​ va returna intotdeauna "​true"​ */ +        crescatoare,​ "​check()"​ va returna intotdeauna "​true"​ */ 
-        if(check(solution)) { +        if(check(solution)) { 
-            printSolution(solution,​ domain, stop); +            printSolution(solution,​ domain, stop); 
-        +        
-        return; +        return; 
-  ​  ​}+    }
  
-    /* daca este primul pas, alegem fiecare element din domeniu ca potential +    ​/* daca este primul pas, alegem fiecare element din domeniu ca potential 
-  ​  ​candidat pentru prima pozitie in solutie; altfel, pentru a elimina ramurile +    candidat pentru prima pozitie in solutie; altfel, pentru a elimina ramurile 
-  ​  ​in care de exemplu {2, 1} se va genera dupa ce s-a generat {1, 2} (adica +    in care de exemplu {2, 1} se va genera dupa ce s-a generat {1, 2} (adica 
-  ​  ​ar fi duplicat), vom folosi doar elementele din domeniu care sunt mai mari +    ar fi duplicat), vom folosi doar elementele din domeniu care sunt mai mari 
-  ​  ​decat ultimul element adaugat in solutie (solution[step - 1]) */ +    decat ultimul element adaugat in solutie (solution[step - 1]) */ 
-  ​  ​unsigned i = step > 0 ? solution[step - 1] + 1 : 0; +    unsigned i = step > 0 ? solution[step - 1] + 1 : 0; 
-  ​  ​for (; i < domain.size();​ ++i) { +    for (; i < domain.size();​ ++i) { 
-        solution[step] = i; +        solution[step] = i; 
-        back(step + 1, stop, domain, solution);​ +        back(step + 1, stop, domain, solution);​ 
-  ​  ​}+    }
 } }
  
 int main() { int main() {
-    /* dupa ce citim n si k initializam domeniul cu valorile de la 1 la n, +    ​/* dupa ce citim n si k initializam domeniul cu valorile de la 1 la n, 
-  ​  ​iar solutia este initializata cu un vector de k elemente (fiindca o +    iar solutia este initializata cu un vector de k elemente (fiindca o 
-  ​  ​combinare de "n luate cate k" are k elemente) */ +    combinare de "n luate cate k" are k elemente) */ 
-  ​  ​std::​vector<​int>​ domain(n), solution(k);​ +    std::​vector<​int>​ domain(n), solution(k);​ 
-  ​  ​for (int i = 0; i < n; ++i) { +    for (int i = 0; i < n; ++i) { 
-        domain[i] = i + 1; +        domain[i] = i + 1; 
-  ​  ​}+    }
  
-    back(0, k, domain, solution);+    ​back(0, k, domain, solution);
 } }
 </​code>​ </​code>​
Line 458: Line 458:
 Soluția va avea următoarele complexități:​ Soluția va avea următoarele complexități:​
  
-  * complexitate temporală : $T(n)=O(Combinari(n,​ k))$ +  ​* complexitate temporală : $T(n)=O(Combinari(n,​ k))$ 
-  * complexitate spatială : $S(n)=O(n+k)=O(n)$ +  * complexitate spatială : $S(n)=O(n+k)=O(n)$ 
-  ​  ​* explicație : $k <= n$, deci $O(n+k)=O(n)$+    * explicație : $k <= n$, deci $O(n+k)=O(n)$
  
 ==== Problema șoricelului ==== ==== Problema șoricelului ====
Line 477: Line 477:
 <spoiler Exemplu 1> <spoiler Exemplu 1>
  
-  * 2 +  ​* 2 
-  * 0 1 +  * 0 1 
-  * 0 0+  * 0 0
  
 Există 1 drum posibil: Există 1 drum posibil:
  
-  * (0, 0)->(1, 0)->(1, 1)+  ​* (0, 0)->(1, 0)->(1, 1)
  
 </​spoiler>​ </​spoiler>​
Line 489: Line 489:
 <spoiler Exemplu 2> <spoiler Exemplu 2>
  
-  * 3 +  ​* 3 
-  * 0 0 0 +  * 0 0 0 
-  * 0 1 0 +  * 0 1 0 
-  * 0 0 0+  * 0 0 0
  
 Există 2 drumuri posibile: Există 2 drumuri posibile:
  
-  * (0,​0)->​(0,​1)->​(0,​2)->​(1,​2)->​(2,​2) +  ​* (0,​0)->​(0,​1)->​(0,​2)->​(1,​2)->​(2,​2) 
-  * (0,​0)->​(1,​0)->​(2,​0)->​(2,​1)->​(2,​2)+  * (0,​0)->​(1,​0)->​(2,​0)->​(2,​1)->​(2,​2)
  
 </​spoiler>​ </​spoiler>​
Line 503: Line 503:
 <spoiler Exemplu 3> <spoiler Exemplu 3>
  
-  * 4 +  ​* 4 
-  * 0 0 0 1 +  * 0 0 0 1 
-  * 0 1 1 0 +  * 0 1 1 0 
-  * 0 0 0 0 +  * 0 0 0 0 
-  * 0 0 0 0+  * 0 0 0 0
  
 Există 4 drumuri posibile: Există 4 drumuri posibile:
  
-  * (0,​0)->​(1,​0)->​(2,​0)->​(2,​1)->​(2,​2)->​(2,​3)->​(3,​3) +  ​* (0,​0)->​(1,​0)->​(2,​0)->​(2,​1)->​(2,​2)->​(2,​3)->​(3,​3) 
-  * (0,​0)->​(1,​0)->​(2,​0)->​(2,​1)->​(2,​2)->​(3,​2)->​(3,​3) +  * (0,​0)->​(1,​0)->​(2,​0)->​(2,​1)->​(2,​2)->​(3,​2)->​(3,​3) 
-  * (0,​0)->​(1,​0)->​(2,​0)->​(2,​1)->​(3,​1)->​(3,​2)->​(3,​3) +  * (0,​0)->​(1,​0)->​(2,​0)->​(2,​1)->​(3,​1)->​(3,​2)->​(3,​3) 
-  * (0,​0)->​(1,​0)->​(2,​0)->​(3,​0)->​(3,​1)->​(3,​2)->​(3,​3)+  * (0,​0)->​(1,​0)->​(2,​0)->​(3,​0)->​(3,​1)->​(3,​2)->​(3,​3)
  
 </​spoiler>​ </​spoiler>​
Line 526: Line 526:
  
 bool check(std::​vector<​std::​pair<​int,​ int> > &​solution,​ int walls[100][100]) { bool check(std::​vector<​std::​pair<​int,​ int> > &​solution,​ int walls[100][100]) {
-    for (unsigned i = 0; i < solution.size() - 1; ++i) { +    ​for (unsigned i = 0; i < solution.size() - 1; ++i) { 
-        /* line_prev si col_prev reprezinta celula in care se afla soricelul la +        /* line_prev si col_prev reprezinta celula in care se afla soricelul la 
-        pasul i; line_next si col_next reprezinta celula in care se afla +        pasul i; line_next si col_next reprezinta celula in care se afla 
-        la pasul i + 1; trebuie sa fim siguri ca soricelul nu a ajuns pe zid +        la pasul i + 1; trebuie sa fim siguri ca soricelul nu a ajuns pe zid 
-        si ca urmatoarea celula este sub sau in dreapta celulei curente */ +        si ca urmatoarea celula este sub sau in dreapta celulei curente */ 
-        int line_prev = solution[i].first;​ +        int line_prev = solution[i].first;​ 
-        int line_next = solution[i + 1].first; +        int line_next = solution[i + 1].first; 
-        int col_prev = solution[i].second;​ +        int col_prev = solution[i].second;​ 
-        int col_next = solution[i + 1].second;+        int col_next = solution[i + 1].second;
  
-        /* walls[x][y] == 1 inseamna ca este zid pe linia x, coloana y */ +        ​/* walls[x][y] == 1 inseamna ca este zid pe linia x, coloana y */ 
-        if (walls[line_prev][col_prev] == 1 || +        if (walls[line_prev][col_prev] == 1 || 
-                !((line_next == line_prev + 1 && col_next == col_prev) || +                !((line_next == line_prev + 1 && col_next == col_prev) || 
-                (line_next == line_prev && col_next == col_prev + 1))) { +                (line_next == line_prev && col_next == col_prev + 1))) { 
-            return false; +            return false; 
-        +        
-  ​  ​}+    }
  
-    return true;+    ​return true;
 } }
  
 void printSolution(std::​vector<​std::​pair<​int,​ int> > &​solution) { void printSolution(std::​vector<​std::​pair<​int,​ int> > &​solution) {
-    for (std::​pair<​int,​ int> s : solution) { +    ​for (std::​pair<​int,​ int> s : solution) { 
-        std::cout << "​("​ << s.first << ","​ << s.second << "​)->";​ +        std::cout << "​("​ << s.first << ","​ << s.second << "​)->";​ 
-  ​  ​+    
-  ​  ​std::cout << "​\n";​+    std::cout << "​\n";​
 } }
  
 void back(std::​vector<​std::​pair<​int,​ int> > &​domain,​ int walls[100][100],​ void back(std::​vector<​std::​pair<​int,​ int> > &​domain,​ int walls[100][100],​
-        std::​vector<​std::​pair<​int,​ int> > &​solution,​ int max_iter) { +        ​std::​vector<​std::​pair<​int,​ int> > &​solution,​ int max_iter) { 
-  ​  ​/* daca am facut "​max_iter"​ pasi ma opresc si verific daca este corecta +    /* daca am facut "​max_iter"​ pasi ma opresc si verific daca este corecta 
-  ​  ​solutia */ +    solutia */ 
-  ​  ​if (solution.size() == max_iter) { +    if (solution.size() == max_iter) { 
-        if(check(solution,​ walls)) { +        if(check(solution,​ walls)) { 
-            printSolution(solution);​ +            printSolution(solution);​ 
-        +        
-        return; +        return; 
-  ​  ​}+    }
  
-    /* avand domeniul initializat cu toate celulele din matrice, incercam sa +    ​/* avand domeniul initializat cu toate celulele din matrice, incercam sa 
-  ​  ​adaugam oricare dintre aceste celule la solutie, verificand la final daca +    adaugam oricare dintre aceste celule la solutie, verificand la final daca 
-  ​  ​solutia este buna */ +    solutia este buna */ 
-  ​  ​for (unsigned int i = 0; i < domain.size();​ ++i) { +    for (unsigned int i = 0; i < domain.size();​ ++i) { 
-        /* pastram elementul curent pentru a-l readauga in domeniu dupa +        /* pastram elementul curent pentru a-l readauga in domeniu dupa 
-        apelarea recursiva */ +        apelarea recursiva */ 
-        std::​pair<​int,​ int> tmp = domain[i];+        std::​pair<​int,​ int> tmp = domain[i];
  
-        /* adaugam elementul curent la solutia candidat */ +        ​/* adaugam elementul curent la solutia candidat */ 
-        solution.push_back(domain[i]);​ +        solution.push_back(domain[i]);​ 
-        /* stergem elementul curent din domeniu */ +        /* stergem elementul curent din domeniu */ 
-        domain.erase(domain.begin() + i);+        domain.erase(domain.begin() + i);
  
-        /* apelam recursiv backtracking */ +        ​/* apelam recursiv backtracking */ 
-        back(domain,​ walls, solution, max_iter);+        back(domain,​ walls, solution, max_iter);
  
-        /* adaugam elementul sters din domeniu inapoi */ +        ​/* adaugam elementul sters din domeniu inapoi */ 
-        domain.insert(domain.begin() + i, tmp); +        domain.insert(domain.begin() + i, tmp); 
-        /* stergem elementul curent din solutia candidat pentru a o forma pe +        /* stergem elementul curent din solutia candidat pentru a o forma pe 
-        urmatoarea */ +        urmatoarea */ 
-        solution.pop_back();​ +        solution.pop_back();​ 
-  ​  ​}+    }
 } }
  
 int main() { int main() {
-    /* initializam domeniul si solutia ca vectori de perechi de int-uri; +    ​/* initializam domeniul si solutia ca vectori de perechi de int-uri; 
-  ​  ​domeniul va contine initial toate perechile de indici posibile din +    domeniul va contine initial toate perechile de indici posibile din 
-  ​  ​matrice ((0, 0), (0, 1) ... (n - 1, n - 1)), iar solutia va fi initial +    matrice ((0, 0), (0, 1) ... (n - 1, n - 1)), iar solutia va fi initial 
-  ​  ​vida */ +    vida */ 
-  ​  ​std::​vector<​std::​pair<​int,​ int> > domain, solution;+    std::​vector<​std::​pair<​int,​ int> > domain, solution;
  
-    fin >> n; +    ​fin >> n; 
-  ​  ​for (i = 0; i < n; ++i) { +    for (i = 0; i < n; ++i) { 
-        for (j = 0; j < n; ++j) { +        for (j = 0; j < n; ++j) { 
-            /* walls[i][j] == 1 daca pe pozitia (i, j) este zid; 0 altfel */ +            /* walls[i][j] == 1 daca pe pozitia (i, j) este zid; 0 altfel */ 
-            fin >> walls[i][j];​ +            fin >> walls[i][j];​ 
-            domain.push_back({i,​ j}); +            domain.push_back({i,​ j}); 
-        +        
-  ​  ​}+    }
  
-    /* apelam back cu domeniul format initial, cu matricea de ziduri, cu +    ​/* apelam back cu domeniul format initial, cu matricea de ziduri, cu 
-  ​  ​solutia vida si cu numarul maxim de iteratii = 2 * n - 1 pentru ca +    solutia vida si cu numarul maxim de iteratii = 2 * n - 1 pentru ca 
-  ​  ​mergand doar in dreapta si in jos, in 2 * n - 1 pasi va ajunge din +    mergand doar in dreapta si in jos, in 2 * n - 1 pasi va ajunge din 
-  ​  ​(0, 0) in (n - 1, n - 1) */ +    (0, 0) in (n - 1, n - 1) */ 
-  ​  ​back(domain,​ walls, solution, 2 * n - 1);+    back(domain,​ walls, solution, 2 * n - 1);
 } }
 </​code>​ </​code>​
Line 620: Line 620:
 Soluția va avea următoarele complexități:​ Soluția va avea următoarele complexități:​
  
-  * complexitate temporală : $T(n)=O(Aranjamente(n^2,​ 2n - 1))$ +  ​* complexitate temporală : $T(n)=O(Aranjamente(n^2,​ 2n - 1))$ 
-  ​  ​* explicație:​ Initial in domeniu avem $n^2$ valori. Noi dorim sa generam toate submultimile ordonate de cate $2n-1$ elemente. Acestea sunt tocmai aranjamentele de $n^2$ luate cate $2n-1$. +    * explicație:​ Initial in domeniu avem $n^2$ valori. Noi dorim sa generam toate submultimile ordonate de cate $2n-1$ elemente. Acestea sunt tocmai aranjamentele de $n^2$ luate cate $2n-1$. 
-  * complexitate spatială : $S(n)=O(n^2)$ +  * complexitate spatială : $S(n)=O(n^2)$ 
-  ​  ​* explicație:​ Trebuie să stocăm informație despre drum, care are $2n-1$ celule; stocăm domeniul care are $n^2$ elemente+    * explicație:​ Trebuie să stocăm informație despre drum, care are $2n-1$ celule; stocăm domeniul care are $n^2$ elemente
  
 === Backtracking (tăierea ramurilor nefolositoare) === === Backtracking (tăierea ramurilor nefolositoare) ===
Line 631: Line 631:
  
 bool check(std::​vector<​std::​pair<​int,​ int> > &​solution) { bool check(std::​vector<​std::​pair<​int,​ int> > &​solution) {
-    return true;+    ​return true;
 } }
  
 void printSolution(std::​vector<​std::​pair<​int,​ int> > &​solution) { void printSolution(std::​vector<​std::​pair<​int,​ int> > &​solution) {
-    for (std::​pair<​int,​ int> s : solution) { +    ​for (std::​pair<​int,​ int> s : solution) { 
-        std::cout << "​("​ << s.first << ","​ << s.second << "​)->";​ +        std::cout << "​("​ << s.first << ","​ << s.second << "​)->";​ 
-  ​  ​+    
-  ​  ​std::cout << "​\n";​+    std::cout << "​\n";​
 } }
  
 void back(int step, int stop, int walls[100][100],​ void back(int step, int stop, int walls[100][100],​
-        std::​vector<​std::​pair<​int,​ int> > &​solution,​ int line_moves[2],​ +        ​std::​vector<​std::​pair<​int,​ int> > &​solution,​ int line_moves[2],​ 
-        int col_moves[2]) { +        int col_moves[2]) { 
-  ​  ​/* ne oprim dupa ce am ajuns la pasul "​stop"​ si verificam daca solutia este +    /* ne oprim dupa ce am ajuns la pasul "​stop"​ si verificam daca solutia este 
-  ​  ​corecta */ +    corecta */ 
-  ​  ​if (step == stop) { +    if (step == stop) { 
-        /* deoarece am eliminat ramurile nefolositoare am ajuns la o solutie care +        /* deoarece am eliminat ramurile nefolositoare am ajuns la o solutie care 
-        sigur este corecta */ +        sigur este corecta */ 
-        if(check(solution)) { +        if(check(solution)) { 
-            printSolution(solution);​ +            printSolution(solution);​ 
-        +        
-        return; +        return; 
-  ​  ​}+    }
  
-    /* daca este primul pas stiu ca soricelul este in pozitia (0, 0) */ +    ​/* daca este primul pas stiu ca soricelul este in pozitia (0, 0) */ 
-  ​  ​if (step == 0) { +    if (step == 0) { 
-        /* adaugam (0, 0) la solutia candidat */ +        /* adaugam (0, 0) la solutia candidat */ 
-        solution.push_back({0,​ 0});+        solution.push_back({0,​ 0});
  
-        /* apelam backtracking recursiv la pasul urmator */ +        ​/* apelam backtracking recursiv la pasul urmator */ 
-        back(step + 1, stop, walls, solution, line_moves, col_moves);+        back(step + 1, stop, walls, solution, line_moves, col_moves);
  
-        /* scoatem (0, 0) din solutie */ +        ​/* scoatem (0, 0) din solutie */ 
-        solution.pop_back();​ +        solution.pop_back();​ 
-        return; +        return; 
-  ​  ​}+    }
  
-    /* sunt doar doua mutari pe care le pot face intr-un pas: dreapta si jos; +    ​/* sunt doar doua mutari pe care le pot face intr-un pas: dreapta si jos; 
-  ​  ​acestea sunt encodate prin vectorii de directii line_moves[2] = {0, 1} si +    acestea sunt encodate prin vectorii de directii line_moves[2] = {0, 1} si 
-  ​  ​col_moves[2] = {1, 0} care reprezinta la indicele 0 miscarea in dreapta, iar +    col_moves[2] = {1, 0} care reprezinta la indicele 0 miscarea in dreapta, iar 
-  ​  ​la indicele 1 miscarea in jos */ +    la indicele 1 miscarea in jos */ 
-  ​  ​for (unsigned int i = 0; i < 2; ++i) { +    for (unsigned int i = 0; i < 2; ++i) { 
-        /* cream noua linie si noua coloana cu ajutorul vectorilor de directii */ +        /* cream noua linie si noua coloana cu ajutorul vectorilor de directii */ 
-        int new_line = solution.back().first + line_moves[i];​ +        int new_line = solution.back().first + line_moves[i];​ 
-        int new_col = solution.back().second + col_moves[i];​ +        int new_col = solution.back().second + col_moves[i];​ 
-        int n = (stop + 1) / 2;+        int n = (stop + 1) / 2;
  
-        /* daca linia si coloana sunt valide (nu ies din matrice) si nu este +        ​/* daca linia si coloana sunt valide (nu ies din matrice) si nu este 
-        zid pe pozitia lor, putem continua pe acea celula */ +        zid pe pozitia lor, putem continua pe acea celula */ 
-        if (new_line < n && new_col < n && walls[new_line][new_col] == 0) { +        if (new_line < n && new_col < n && walls[new_line][new_col] == 0) { 
-            /* adaugam noua celula in solutia candidat; +            /* adaugam noua celula in solutia candidat; 
-            NOTE: {new_line, new_col} este echivalent cu +            NOTE: {new_line, new_col} este echivalent cu 
-            std::​pair<​int,​ int>​(new_line,​ new_col) si se numeste "​initializer +            std::​pair<​int,​ int>​(new_line,​ new_col) si se numeste "​initializer 
-            list", feature in C++11 */ +            list", feature in C++11 */ 
-            solution.push_back({new_line,​ new_col});+            solution.push_back({new_line,​ new_col});
  
-            /* apelam backtracking recursiv la pasul urmator */ +            ​/* apelam backtracking recursiv la pasul urmator */ 
-            back(step + 1, stop, walls, solution, line_moves, col_moves);+            back(step + 1, stop, walls, solution, line_moves, col_moves);
  
-            /* scoatem celula adaugata din solutie */ +            ​/* scoatem celula adaugata din solutie */ 
-            solution.pop_back();​ +            solution.pop_back();​ 
-        +        
-  ​  ​}+    }
 } }
  
 int main() { int main() {
-    /* initializam solutia ca vector de perechi de int-uri */ +    ​/* initializam solutia ca vector de perechi de int-uri */ 
-  ​  ​std::​vector<​std::​pair<​int,​ int> > solution;+    std::​vector<​std::​pair<​int,​ int> > solution;
  
-    fin >> n; +    ​fin >> n; 
-  ​  ​for (i = 0; i < n; ++i) { +    for (i = 0; i < n; ++i) { 
-        for (j = 0; j < n; ++j) { +        for (j = 0; j < n; ++j) { 
-            /* citim matricea zidurilor; 1 pentru zid, 0 altfel */ +            /* citim matricea zidurilor; 1 pentru zid, 0 altfel */ 
-            fin >> walls[i][j];​ +            fin >> walls[i][j];​ 
-        +        
-  ​  ​}+    }
  
-    /* apelam back cu step = 0, stop = 2 * n - 1 deoarece in 2 * n - 1 +    ​/* apelam back cu step = 0, stop = 2 * n - 1 deoarece in 2 * n - 1 
-  ​  ​pasi soricelul va ajunge la branza, vectorul de ziduri, vectorul in +    pasi soricelul va ajunge la branza, vectorul de ziduri, vectorul in 
-  ​  ​care vom stoca solutia, vectorii de directii line_moves[2] = {0, 1} si +    care vom stoca solutia, vectorii de directii line_moves[2] = {0, 1} si 
-  ​  ​col_moves[2] = {1, 0}; nu avem nevoie de domeniu deoarece folosind +    col_moves[2] = {1, 0}; nu avem nevoie de domeniu deoarece folosind 
-  ​  ​vectorii de directii vom sti din ultima pozitie pusa in solutie cele +    vectorii de directii vom sti din ultima pozitie pusa in solutie cele 
-  ​  ​doua solutii in care putem merge, astfel domeniul nostru va fi alcatuit +    doua solutii in care putem merge, astfel domeniul nostru va fi alcatuit 
-  ​  ​din doua solutii la fiecare pas (daca ultima pozitie din solutie a fost +    din doua solutii la fiecare pas (daca ultima pozitie din solutie a fost 
-  ​  ​(5, 7) => domeniul pasului curent = {(5 + 0, 7 + 1) si (5 + 1, 7 + 0)} +    (5, 7) => domeniul pasului curent = {(5 + 0, 7 + 1) si (5 + 1, 7 + 0)} 
-  ​  ​care este egal cu {(5, 8), (6, 7)}. */ +    care este egal cu {(5, 8), (6, 7)}. */ 
-  ​  ​back(0, 2 * n - 1, walls, solution, line_moves, col_moves);+    back(0, 2 * n - 1, walls, solution, line_moves, col_moves);
 } }
  
Line 730: Line 730:
 Soluția va avea urmatoarele complexitati:​ Soluția va avea urmatoarele complexitati:​
  
-  * complexitate temporală : $T(n)=O(2^{2n})$ +  ​* complexitate temporală : $T(n)=O(2^{2n})$ 
-      * explicație:​ avem de urmat un șir de $2n-1$ mutari, iar la fiecare pas avem 2 variante posibile +      * explicație:​ avem de urmat un șir de $2n-1$ mutari, iar la fiecare pas avem 2 variante posibile 
-  * complexitate spatiala : $S(n)=O(n)$ +  * complexitate spatiala : $S(n)=O(n)$ 
-      * explicație:​ stocam maximum $2n-1$ căsuțe+      * explicație:​ stocam maximum $2n-1$ căsuțe
  
 ===== Pool probleme (pentru prezentări) ====== ===== Pool probleme (pentru prezentări) ======
Line 739: Line 739:
 ======= 1) Word Search ======= ======= 1) Word Search =======
  
-**Enunt:** Se dă o matrice de dimensiuni ''​m × n''​ formată din litere și un cuvânt ''​word''​. Determinați dacă acest cuvânt poate fi format în matrice.  +**Enunt:** Se dă o matrice de dimensiuni ''​m × n''​ formată din litere și un cuvânt ''​word''​. Determinați dacă acest cuvânt poate fi format în matrice. ​ 
 Cuvântul se construiește unind litere din celule adiacente (pe orizontală sau verticală). Nu aveți voie să folosiți aceeași celulă de două ori în formarea aceluiași cuvânt. Cuvântul se construiește unind litere din celule adiacente (pe orizontală sau verticală). Nu aveți voie să folosiți aceeași celulă de două ori în formarea aceluiași cuvânt.
  
Line 746: Line 746:
 **Date de ieșire:** Se afișează ''​true''​ dacă cuvântul există în matrice, altfel ''​false''​. **Date de ieșire:** Se afișează ''​true''​ dacă cuvântul există în matrice, altfel ''​false''​.
  
-Problema se poate testa la:  +Problema se poate testa la:  
 https://​leetcode.com/​problems/​word-search/​ https://​leetcode.com/​problems/​word-search/​
  
 ======= 2) Combination Sum II ======= ======= 2) Combination Sum II =======
  
-**Enunt:** Se dă un șir de numere (care poate conține duplicate) și un număr țintă ''​target''​. Găsiți toate combinațiile unice de elemente din șir a căror sumă este exact ''​target''​.  +**Enunt:** Se dă un șir de numere (care poate conține duplicate) și un număr țintă ''​target''​. Găsiți toate combinațiile unice de elemente din șir a căror sumă este exact ''​target''​. ​ 
 Fiecare element de pe o anumită poziție din șir poate fi folosit cel mult o dată într-o combinație. Setul final de soluții nu trebuie să conțină combinații duplicate. Fiecare element de pe o anumită poziție din șir poate fi folosit cel mult o dată într-o combinație. Setul final de soluții nu trebuie să conțină combinații duplicate.
  
Line 758: Line 758:
 **Date de ieșire:** O listă de liste de numere întregi, reprezentând combinațiile unice valide. **Date de ieșire:** O listă de liste de numere întregi, reprezentând combinațiile unice valide.
  
-Problema se poate testa la:  +Problema se poate testa la:  
 https://​leetcode.com/​problems/​combination-sum-ii/​ https://​leetcode.com/​problems/​combination-sum-ii/​
  
 ======= 3) Gray Code ======= ======= 3) Gray Code =======
  
-**Enunt:** Codul Gray de ordin ''​n''​ este o secvență ce conține toate cele $2^n$ șiruri binare de lungime ''​n'',​ cu proprietatea că oricare două șiruri consecutive diferă prin exact un singur bit.   +**Enunt:** Codul Gray de ordin ''​n''​ este o secvență ce conține toate cele $2^n$ șiruri binare de lungime ''​n'',​ cu proprietatea că oricare două șiruri consecutive diferă prin exact un singur bit.   
-Cerința este să generați o astfel de secvență validă pentru un ''​n''​ dat. +Cerința este să generați o astfel de secvență validă pentru un ''​n''​ dat. 
  
 **Date de intrare:** Un număr întreg ''​n''​ — lungimea șirurilor de biți. **Date de intrare:** Un număr întreg ''​n''​ — lungimea șirurilor de biți.
Line 770: Line 770:
 **Date de ieșire:** Se afișează secvența de $2^n$ numere (în format zecimal sau binar), respectând regula codului Gray. **Date de ieșire:** Se afișează secvența de $2^n$ numere (în format zecimal sau binar), respectând regula codului Gray.
  
-Problema se poate testa la:  +Problema se poate testa la:  
 https://​cses.fi/​problemset/​task/​2205 https://​cses.fi/​problemset/​task/​2205
  
 ======= 4) Sudoku Solver ======= ======= 4) Sudoku Solver =======
  
-**Enunt:** Vi se cere să scrieți un program care rezolvă un puzzle Sudoku clasic (9 × 9) prin completarea celulelor goale.  +**Enunt:** Vi se cere să scrieți un program care rezolvă un puzzle Sudoku clasic (9 × 9) prin completarea celulelor goale. ​ 
 Pentru ca soluția să fie validă, trebuie respectate regulile clasice: fiecare cifră de la 1 la 9 trebuie să apară o singură dată pe fiecare rând, pe fiecare coloană și în fiecare dintre cele nouă careuri 3 × 3. Pentru ca soluția să fie validă, trebuie respectate regulile clasice: fiecare cifră de la 1 la 9 trebuie să apară o singură dată pe fiecare rând, pe fiecare coloană și în fiecare dintre cele nouă careuri 3 × 3.
  
Line 782: Line 782:
 **Date de ieșire:** Matricea 9 × 9 completată cu soluția corectă. **Date de ieșire:** Matricea 9 × 9 completată cu soluția corectă.
  
-Problema se poate testa la:  +Problema se poate testa la:  
 https://​leetcode.com/​problems/​sudoku-solver/​ https://​leetcode.com/​problems/​sudoku-solver/​
  
 ======= 5) Palindrome Partitioning ======= ======= 5) Palindrome Partitioning =======
  
-**Enunt:** Se dă un șir de caractere ''​s''​. Se cere să împărțiți șirul în fragmente, astfel încât fiecare fragment (subșir) rezultat să fie un palindrom.  +**Enunt:** Se dă un șir de caractere ''​s''​. Se cere să împărțiți șirul în fragmente, astfel încât fiecare fragment (subșir) rezultat să fie un palindrom. ​ 
 Returnați toate aceste partiționări posibile. Returnați toate aceste partiționări posibile.
  
Line 794: Line 794:
 **Date de ieșire:** O listă de liste de șiruri de caractere, unde fiecare listă interioară reprezintă o partiționare validă. **Date de ieșire:** O listă de liste de șiruri de caractere, unde fiecare listă interioară reprezintă o partiționare validă.
  
-Problema se poate testa la:  +Problema se poate testa la:  
 https://​leetcode.com/​problems/​palindrome-partitioning/​ https://​leetcode.com/​problems/​palindrome-partitioning/​
  
Line 819: Line 819:
  
 Soluție: Soluție:
-  * {1, 2} +  ​* {1, 2} 
-  * {1, 3} +  * {1, 3} 
-  * {2, 1} +  * {2, 1} 
-  * {2, 3} +  * {2, 3} 
-  * {3, 1} +  * {3, 1} 
-  * {3, 2}+  * {3, 2}
  
 <​note>​ <​note>​
Line 895: Line 895:
  
 <​note>​ <​note>​
-Se va caută o singură soluție  (**oricare** soluție corectă), care va fi returnată sub forma unui vector cu $n + 1$ elemente.+Se va caută o singură soluție  ​(**oricare** soluție corectă), care va fi returnată sub forma unui vector cu $n + 1$ elemente.
  
 Soluția este $sol[0], sol[1], ..., sol[n]$, unde $sol[i]$ = coloana unde vom plasa regina de pe linia i. Soluția este $sol[0], sol[1], ..., sol[n]$, unde $sol[i]$ = coloana unde vom plasa regina de pe linia i.
Line 913: Line 913:
  
 Soluție: Soluție:
-  * abcc +  ​* abcc 
-  * acbc +  * acbc 
-  * accb +  * accb 
-  * bacc +  * bacc 
-  * bcac +  * bcac 
-  * bcca +  * bcca 
-  * cabc +  * cabc 
-  * cacb +  * cacb 
-  * cbac +  * cbac 
-  * cbca +  * cbca 
-  * ccab +  * ccab 
-  * ccba+  * ccba
  
 **Exemplu 2:** **Exemplu 2:**
Line 930: Line 930:
  
 Solutie: Solutie:
-  * bbcbc +  ​* bbcbc 
-  * bbccb +  * bbccb 
-  * bcbbc +  * bcbbc 
-  * bcbcb +  * bcbcb 
-  * bccbb +  * bccbb 
-  * cbbcb +  * cbbcb 
-  * cbcbb+  * cbcbb
  
 <​note>​ <​note>​
Line 944: Line 944:
 </​note>​ </​note>​
 </​spoiler>​ </​spoiler>​
- 
-==== Bonus ==== 
  
 <spoiler Problema damelor (AC3)> <spoiler Problema damelor (AC3)>
Line 953: Line 951:
  
 AC-3 lucrează cu: AC-3 lucrează cu:
-    * constrângeri +    ​* constrângeri 
-  ​  ​* variabile +    * variabile 
-  ​  ​* domenii de variabile+    * domenii de variabile
  
 O variabilă poate lua orice valoare din domeniul său la orice pas. O constrângere este o relație sau o limitare a unor variabile. O variabilă poate lua orice valoare din domeniul său la orice pas. O constrângere este o relație sau o limitare a unor variabile.
pa/laboratoare/laborator-04.1774569442.txt.gz · Last modified: 2026/03/27 01:57 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