Differences

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

Link to this comparison view

pa:laboratoare:laborator-05 [2019/03/26 12:01]
teodor_mihai.cotet [Referinte]
pa:laboratoare:laborator-05 [2024/04/01 14:12] (current)
radu.nichita
Line 1: Line 1:
-====== Laborator 5: Backtracking ====== +====== Laborator 05: Backtracking ====== 
-Responsabili:​ + 
-  * [[radu.stochitoiu@gmail.com|Radu Stochitoiu]] +
-  * [[razvan.m.chitu@gmail.com|Razvan Chitu]] +
 ===== Obiective laborator ===== ===== Obiective laborator =====
-  * Intelegerea notiunilor ​de baza despre backtracking;​ +  * Întelegerea noțiunilor ​de bază despre backtracking;​ 
-  * Insusirea abilitatilor ​de implementare a algoritmilor ​bazati ​backtracking;​ +  * Însușirea abilităților ​de implementare a algoritmilor ​bazați pe backtracking;​ 
-  * Rezolvarea unor probleme NP-complete în timp exponential.+  * Rezolvarea unor probleme NP-complete în timp exponențial.
  
-===== Precizari initiale ​=====+===== Precizări inițiale ​=====
 <​note>​ <​note>​
-Toate exemplele de cod se gasesc in {{pa:new_pa:demo-lab05.zip}}+Toate exemplele de cod se găsesc pe pagina [[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​demo/​lab05|pa-lab::demo/lab05]]
-Acestea ​apar incorporate si in textul laboratorului pentru a facilita parcurgerea ​cursiva ​laboratorului.+ 
 +Exemplele de cod apar încorporate și în textul laboratorului pentru a facilita parcurgerea ​cursivă ​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.
 +  * 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.
 +
  
 ===== Ce este Backtracking?​ ===== ===== Ce este Backtracking?​ =====
-Backtracking este un algoritm care cauta **una sau mai multe solutii** pentru o problema, printr-o ​cautare ​exhaustiva, mai eficienta insa in general ​decat o abordare „genereaza ​si testeaza”, de tip „forta bruta”, deoarece un candidat ​partial ​care nu duce la o solutie ​este abandonat. Poate fi folosit pentru orice problema ​care presupune o cautare in **spatiul starilor**. +Backtracking este un algoritm care caută ​**una sau mai multe soluții** pentru o problema, printr-o ​căutare ​exhaustiva, mai eficientă însă în general ​decât ​o abordare „generează ​si testează”, de tip „forță brută”, deoarece un candidat ​parțial ​care nu duce la o soluție ​este abandonat. Poate fi folosit pentru orice problemă ​care presupune o căutare în **spațiul stărilor**. 
-In general, ​in timp ce cautam ​solutie ​e posibil ​sa dam de o infundatura in urma unei alegeri ​gresite ​sau sa gasim solutie, dar sa dorim sa cautam in continuare alte solutiiIn acel moment trebuie ​sa ne intoarcem ​pe pasii facuti ​(**backtrack**) ​si la un moment dat sa luam alta decizie. +În general, ​în timp ce cautăm ​soluție ​e posibil ​să dăm de un deadend în urma unei alegeri ​greșite ​sau să găsim ​soluție, dar să dorim să căutăm în continuare alte soluțiiÎn acel moment trebuie ​să ne întoarcem ​pe pașii făcuți ​(**backtrack**) ​și la un moment dat să luăm altă decizie. 
-Este relativ simplu din punct de vedere conceptual, dar complexitatea algoritmului este exponentiala.+Este relativ simplu din punct de vedere conceptual, dar complexitatea algoritmului este exponentială.
  
-===== Importanţa – aplicaţii practice ===== +===== Importanța – aplicaţii practice ===== 
-Exista ​foarte multe probleme (de exemplu, ​probleme ​NP-complete sau NP-dificile) care pot fi rezolvate prin algoritmi de tip backtracking mai eficient ​decat prin „forta bruta” (adica generarea tuturor alternativelor ​si selectarea ​solutiilor). Atentie insa, complexitatea ​computationala ​este de cele mai multe ori exponentiala. O eficientizare se poate face prin combinarea cu tehnici de propagare a restrictiilor. Orice problema ​care are nevoie de parcurgerea ​spatiului ​de stari 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 ​si rezolvarilor ​===== +===== Descrierea problemei ​și rezolvărilor ​===== 
-Pornind de la strategiile clasice de parcurgere a **spatiului ​de stari**, algoritmii de tip backtracking practic ​enumera ​un set de candidati partiali, care, dupa completarea ​definitiva, pot deveni ​solutii potentiale ​ale problemei ​initiale. Exact ca strategiile de **parcurgere în latime/adancime** si backtracking-ul are la baza expandarea unui nod curent, iar determinarea ​solutiei ​se face într-o ​maniera incrementala. Prin natura sa, backtracking-ul este recursiv, iar în arborele expandat top-down se aplica operatii ​de tipul pruning (taieredaca solutia partiala ​nu este valida.+Pornind de la strategiile clasice de parcurgere a **spațiului ​de stări**, algoritmii de tip backtracking practic ​enumeră ​un set de candidați parțiali, care, după completarea ​definitivă, pot deveni ​soluții potențiale ​ale problemei ​inițiale. Exact ca strategiile de **parcurgere în lățime/adâncime** și backtracking-ul are la bază expandarea unui nod curent, iar determinarea ​soluției ​se face într-o ​manieră incrementală. Prin natura sa, backtracking-ul este recursiv, iar în arborele expandat top-down se aplică operații ​de tipul pruning (tăieredacă soluția parțială ​nu este validă.
  
 ===== Algoritm de baza ===== ===== Algoritm de baza =====
Line 68: Line 71:
  
 ===== Exemple clasice ===== ===== Exemple clasice =====
-Ne vom ocupa in continuare de urmatoarele ​probleme: +Ne vom ocupa în continuare de următoarele ​probleme: 
-  * Permutari +  * Permutări 
-  * Combinari+  * Combinări
   * Aranjamente   * Aranjamente
-  * Submultimi +  * Submulțimi 
-  * Genererare ​de siruri+  * Generare ​de șiruri
   * Problema damelor   * Problema damelor
-  * Problema ​soricelului+  * Problema ​șoricelului
   * Tic-Tac-Toe   * Tic-Tac-Toe
   * Sudoku   * Sudoku
Line 81: Line 84:
  
 <​note>​ <​note>​
-Sudoku ​si Ultimate Tic-Tac-Toe sunt probleme foarte grele. ​In general nu putem explora tot spatiul starilor ​pentru un input arbitrar dat.+Sudoku ​și Ultimate Tic-Tac-Toe sunt probleme foarte grele. ​În general nu putem explora tot spațiul stărilor ​pentru un input arbitrar dat.
 </​note>​ </​note>​
  
-==== Permutari ​====+==== Permutări ​====
  
-=== Enunt ===+=== Enunț ​===
  
-Se da un numar N. Sa se genereze toate permutarile multimii ​formate din toate numerele de la 1 la N.+Se dă un număr ​N. Să se genereze toate permutările mulțimii ​formate din toate numerele de la 1 la N.
  
 === Exemple === === Exemple ===
Line 106: Line 109:
 </​spoiler>​ </​spoiler>​
  
-=== Solutii ​===+=== Soluții ​===
  
-=== Backtracking (algoritmul ​in cazul general) ===+=== Backtracking (algoritmul ​în cazul general) ===
 <spoiler Implementare>​ <spoiler Implementare>​
  
 <code cpp> <code cpp>
-/* deoarece numerele sunt sterse din domeniu odata ce sunt folosite, ​solutia ​generata este garantata +/* 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, solutia ​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;
Line 119: Line 122:
  
 void printSolution(std::​vector<​int>​ solution) { void printSolution(std::​vector<​int>​ solution) {
-    for (int s : solution) {+    for (auto &s : solution) {
         std::cout << s << " ";         std::cout << s << " ";
     }     }
Line 164: Line 167:
 </​code>​ </​code>​
  
-Apelarea ​initiala ​(din "int main") se face astfel: "​back(domain,​ solution);",​ unde domain ​reprezinta ​un vector cu elementele de la 1 la N, iar solution este un vector gol.+Apelarea ​inițială ​(din "​main"​) se face astfel: "​back(domain,​ solution);",​ unde domain ​reprezintă ​un vector cu elementele de la 1 la N, iar solution este un vector gol.
  
 <note important>​ <note important>​
-Nu este indicata ​implementarea backtracking-ului astfel deoarece este foarte costisitor din punct de vedere al memoriei, deoarece cream noi domenii ​si solutii ​la fiecare pas.+Nu este indicată ​implementarea backtracking-ului astfel deoarece este foarte costisitor din punct de vedere al memoriei(se creează ​noi domenii ​și soluții ​la fiecare pas).
 </​note>​ </​note>​
- 
  
 </​spoiler>​ </​spoiler>​
Line 175: Line 177:
 == Complexitate == == Complexitate ==
  
-Solutia ​va avea urmatoarele ​complexitati:​+Soluția ​va avea următoarele ​complexitati:​
  
-  * complexitate temporala : $T(n)=O(n * n!)=O(n!)$ +  * complexitate temporala : $T(n)=O(n * n!)$ 
-     ​* ​explicatie ​Complexitate ​generarii permutarilor,​ $O(n!)$, se inmulteste ​cu complexitatea copierii vectorilor ​solutie ​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)$
-     ​* ​explicatie ​: Fiecare nivel de recursivitate are propria lui copie a solutiei si a domeniului. Sunt n nivele de recursivitate,​ deci complexitatea ​spatiala ​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 188: Line 190:
 <code cpp> <code cpp>
  
-/* deoarece numerele sunt sterse din domeniu odata ce sunt folosite, ​solutia ​generata este garantata sa nu contina duplicate. Astfel, atunci cand domeniul ajunge vid, solutia ​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;
Line 252: Line 254:
 == Complexitate == == Complexitate ==
  
-Solutia ​va avea urmatoarele complexitati:+Soluția ​va avea următoarele complexități:
  
-  * complexitate ​temporala ​: $T(n)=O(n * n!)$ +  * complexitate ​temporală ​: $T(n)=O(n * n!)$ 
-    * explicatie ​Complexitate generarii permutarilor, $O(n!)$, se inmulteste ​cu complexitatea ​stergerii ​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 ​spatiala ​: $S(n)=O(n)$ +  * complexitate ​spatială ​: $S(n)=O(n)$ 
-    * explicatie ​: Spre deosebire de solutia ​anterioara, toate nivelele de recursivitate folosesc ​aceeasi solutie si acelasi ​domeniu. Complexitatea ​spatiala ​este astfel ​redusa ​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>​
  
-Abordarea aceasta ​este mai eficienta decat cea generala prin evitarea folosirii ​memoriei auxiliare.+Această abordare ​este mai eficientă decât ​cea generală, deoarece se evită folosirea ​memoriei auxiliare.
  
 </​note>​ </​note>​
  
  
-=== Backtracking (taierea ​ramurilor nefolositoare) ===+=== Backtracking (tăierea ​ramurilor nefolositoare) ===
 <spoiler Implementare>​ <spoiler Implementare>​
  
Line 343: Line 345:
 </​code>​ </​code>​
  
-Apelarea ​initiala ​(din "int main") se face astfel: "​back(0,​ n, domain, solution, visited);",​ unde domain ​reprezinta ​un vector cu elementele de la 1 la N, iar solution este un vector de n elemente, 0 este pasul curent, n este pasul la care dorim sa ne oprim, iar visited este map-ul care ne permite ​sa tinem cont de ce elemente au fost vizitate sau nu.+Apelarea ​inițială ​(din "​main"​) se face astfel: "​back(0,​ n, domain, solution, visited);",​ unde domain ​reprezintă ​un vector cu elementele de la 1 la N, iar solution este un vector de n elemente, 0 este pasul curent, n este pasul la care dorim să ne oprim, iar visited este map-ul care ne permite ​să ținem ​cont de ce elemente au fost vizitate sau nu.
  
 </​spoiler>​ </​spoiler>​
  
-=== Complexitate ​===+== Complexitate ==
  
-Solutia ​va avea urmatoarele complexitati:+Soluția ​va avea următoarele complexitați:
  
-  * complexitate ​temporala ​: $T(n)=O(n * n!)=O(n!)$ +  * complexitate ​temporală ​: $T(n)=O(n * n!)=O(n!)$ 
-    * explicatie ​Complexitate generarii permutarilor, O(n!), se inmulteste ​cu complexitatea +    * explicație ​Complexitatea generării permutărilor, O(n!), se înmulțește ​cu complexitatea ​iterării ​prin domeniu, $O(n)$ 
-    iterarii ​prin domeniu, $O(n)$ +  * complexitate ​spatială ​: $S(n)=O(n)$ 
-  * complexitate ​spatiala ​: $S(n)=O(n)$ +    * explicație ​: Toate nivelele de recursivitate folosesc ​aceeași soluție și același ​domeniu.
-    * explicatie ​: Toate nivelele de recursivitate folosesc ​aceeasi solutie si acelasi ​domeniu.+
  
 <​note>​ <​note>​
  
-Aceasta solutie ​este optima si are complexitate temporala ​$T(n) = O(n!)$. Nu putem sa obtinem ​solutie ​mai bunaintrucat ​trebuie ​sa generam ​n! permutari.+Această soluție ​este optimă și are complexitatea temporală ​$T(n) = O(n!)$. Nu putem să obținem ​soluție ​mai bunăîntrucât ​trebuie ​să generăm ​n! permutări.
  
- +De asemenea, este optimă și din punct de vedere spatial, ​întrucât ​trebuie ​să avem $S(n) = O(n)$, din cauza stocării permutării ​generate.
-De asemenea, este optima si din punct de vedere spatial, ​intrucat ​trebuie ​sa avem $S(n) = O(n)$, din cauza stocarii permutarii ​generate.+
 </​note>​ </​note>​
  
  
-==== Combinari ​====+==== Combinări ​====
  
-=== Enunt ===+=== Enunț ​===
  
-Se dau numerele N si K. Sa se genereze toate combinarile multimii ​formate din toate numerele de la 1 la N, luate cate K.+Se dau numerele N si K. Să se genereze toate combinările mulțimii ​formate din toate numerele de la 1 la N, luate câte K.
  
 === Exemple === === Exemple ===
Line 378: Line 378:
 N = 4, K = 2 => M = {1, 2, 3, 4} N = 4, K = 2 => M = {1, 2, 3, 4}
  
-Solutie:+Soluție:
   * {1, 2}   * {1, 2}
   * {1, 3}   * {1, 3}
Line 388: Line 388:
 </​spoiler>​ </​spoiler>​
  
-=== Solutii ​===+=== Soluții ​===
  
-===Backtracking (taierea ​ramurilor nefolositoare) ===+===Backtracking (tăierea ​ramurilor nefolositoare) ===
 <spoiler Implementare>​ <spoiler Implementare>​
 <code cpp> <code cpp>
Line 443: Line 443:
 </​code>​ </​code>​
  
-In aceasta solutie ​ne bazam pe faptul ​ca toate combinarile ​pot fi generate ​in +În această soluție ​ne bazăm ​pe faptul ​că toate combinările ​pot fi generate ​în 
-ordine ​crescatoareadica solutia ​{1, 3, 4} e echivalenta ​cu {4, 1, 3}.+ordine ​crescătoareadică soluția ​{1, 3, 4} e echivalentă ​cu {4, 1, 3}.
  
 <​note>​ <​note>​
  
-Aceasta solutie ​este optima intrucat ​toate solutiile ​generate sunt corecte (de aceea functia ​check intoarce ​true). Deoarece problema cere obtinerea ​tuturor ​combinarilor, aceasta complexitate nu poate fi mai mica de Combinari(n, k).+Această soluție ​este optimă întrucât ​toate soluțiile ​generate sunt corecte (de aceea funcția ​check întoarce ​true). Deoarece problema cere obținerea ​tuturor ​combinărilor, aceasta complexitate nu poate fi mai mică de Combinări(n, k).
  
 </​note>​ </​note>​
Line 456: Line 456:
 === Complexitate === === Complexitate ===
  
-Solutia ​va avea urmatoarele complexitati:+Soluția ​va avea următoarele complexități:
  
-  * complexitate ​temporala ​: $T(n)=O(Combinari(n,​ k))$ +  * complexitate ​temporală ​: $T(n)=O(Combinari(n,​ k))$ 
-  * complexitate ​spatiala ​: $S(n)=O(n+k)=O(n)$ +  * complexitate ​spatială ​: $S(n)=O(n+k)=O(n)$ 
-    * explicatie ​: $k <= n$, deci $O(n+k)=O(n)$+    * explicație ​: $k <= n$, deci $O(n+k)=O(n)$
  
-==== Problema ​soricelului ​====+==== Problema ​șoricelului ​====
  
-=== Enunt ===+=== Enunț ​===
  
-Se da un numar si o matrice ​patratica ​de dimensiuni N x N in care elementele +Se dă un număr ​și o matrice ​pătratică ​de dimensiuni N x N în care elementele 
-egale cu 1 reprezinta ​ziduri (locuri prin care nu se poate trece), iar cele egale +egale cu 1 reprezintă ​ziduri (locuri prin care nu se poate trece), iar cele egale 
-cu 0 reprezinta spatii ​goale. ​Aceasta ​matrice are un soricel in celula (0, 0) si +cu 0 reprezintă spații ​goale. ​Această ​matrice are un șoricel în celula (0, 0) și 
-bucata ​de branza in celula (N - 1, N - 1). Scopul ​soricelului ​sa ajunga ​la +bucată ​de brânză în celula (N - 1, N - 1). Scopul ​șoricelului ​să ajungă ​la 
-bucata de branzaAfisati ​toate modurile ​in care poate face asta stiind ca +bucata de brânzăAfișați ​toate modurile ​în care poate face asta știind că 
-acesta poate merge doar in dreapta sau in jos cu cate celula ​la fiecare pas.+acesta poate merge doar în dreapta sau în jos cu câte celulă ​la fiecare pas.
  
 === Exemple === === Exemple ===
Line 481: Line 481:
   * 0 0   * 0 0
  
-Exista ​1 drum posibil:+Există ​1 drum posibil:
  
   * (0, 0)->(1, 0)->(1, 1)   * (0, 0)->(1, 0)->(1, 1)
Line 494: Line 494:
   * 0 0 0   * 0 0 0
  
-Exista ​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)
Line 509: Line 509:
   * 0 0 0 0   * 0 0 0 0
  
-Exista ​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)
Line 518: Line 518:
 </​spoiler>​ </​spoiler>​
  
-=== Solutii ​===+=== Soluții ​===
  
-=== Backtracking (transmitere prin referinta) ===+=== Backtracking (transmitere prin referință) ===
 <spoiler Implementare>​ <spoiler Implementare>​
  
Line 618: Line 618:
 === Complexitate === === Complexitate ===
  
-Solutia ​va avea urmatoarele complexitati:+Soluția ​va avea următoarele complexități:
  
-  * complexitate ​temporala ​: $T(n)=O(Aranjamente(n^2,​ 2n - 1))$ +  * complexitate ​temporală ​: $T(n)=O(Aranjamente(n^2,​ 2n - 1))$ 
-    * explicatie: 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 ​spatiala ​: $S(n)=O(n^2)$ +  * complexitate ​spatială ​: $S(n)=O(n^2)$ 
-    * explicatie: Trebuie ​sa stocam informatie ​despre drum, care are $2n-1$ celule; ​stocam ​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^2elemente
  
-=== Backtracking (taierea ​ramurilor nefolositoare) ===+=== Backtracking (tăierea ​ramurilor nefolositoare) ===
 <spoiler Implementare>​ <spoiler Implementare>​
  
Line 728: Line 728:
 === Complexitate === === Complexitate ===
  
-Solutia ​va avea urmatoarele complexitati:​+Soluția ​va avea urmatoarele complexitati:​
  
-  * complexitate ​temporala ​: $T(n)=O(2^{2n})$ +  * complexitate ​temporală ​: $T(n)=O(2^{2n})$ 
-      * explicatie: avem de urmat un sir 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)$
-      * explicatie: stocam maximum $2n-1$ ​casute+      * explicație: stocam maximum $2n-1$ ​căsuțe
  
-===== Exercitii ​=====+===== Exerciții ​=====
 <​note>​ <​note>​
-In acest laborator vom folosi scheletul ​de laborator ​din arhiva {{pa:new_pa:skel-lab05.zip}}.+Scheletul ​de laborator ​se găsește pe pagina [[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​skel/​lab05|pa-lab::skel/lab05]].
 </​note>​ </​note>​
- 
 ==== Aranjamente ==== ==== Aranjamente ====
-Fie N si doua **numere naturale strict pozitive**. Se cere afisarea ​tuturor aranjamentelor de N elemente luate cate K din multimea ​{1, 2, ..., N}.+Fie N și două **numere naturale strict pozitive**. Se cere afișarea ​tuturor aranjamentelor de N elemente luate cate K din mulțimea ​{1, 2, ..., N}.
  
 <spoiler Exemplu 1> <spoiler Exemplu 1>
Line 747: Line 746:
 Fie N = 3, K = 2 => M = {1, 2, 3} Fie N = 3, K = 2 => M = {1, 2, 3}
  
-Solutie:+Soluție:
   * {1, 2}   * {1, 2}
   * {1, 3}   * {1, 3}
Line 758: Line 757:
  
 <​note>​ <​note>​
-Se doreste ​o complexitate $T(n, k) = A(n,k)$.+Se dorește ​o complexitate $T(n, k) = A(n,k)$.
 </​note>​ </​note>​
  
 <spoiler Hint> <spoiler Hint>
-Folositi-va de problema **Permutari**.+Folosiți-vă de problema **Permutări**.
 </​spoiler>​ </​spoiler>​
  
  
 <​note>​ <​note>​
-Solutiile ​se vor genera ​in ordine lexico-grafica!+Soluțiile ​se vor genera ​în ordine lexico-grafica!
  
-Checkerul ​asteapta sa le stocati in aceasta ​ordine.+Checkerul ​așteaptă să le stocați în această ​ordine.
 </​note>​ </​note>​
  
-==== Submultimi ​==== +==== Submulțimi ​==== 
-Fie N un **numar natural strict pozitiv**. Se cere afisarea ​tuturor ​submultimilor multimii ​{1, 2, ..., N}.+Fie N un **număr ​natural strict pozitiv**. Se cere afișarea ​tuturor ​submulțimilor mulțimii ​{1, 2, ..., N}.
  
 <spoiler Exemplu 1> <spoiler Exemplu 1>
Line 779: Line 778:
 Fie N = 4 => M = {1, 2, 3, 4} Fie N = 4 => M = {1, 2, 3, 4}
  
-Solutie+Soluție
-{} - multimea vida+{} - mulțimea vidă
 {1} {1}
 {1, 2} {1, 2}
Line 801: Line 800:
  
 <​note>​ <​note>​
-Se doreste ​o complexitate $T(n) = O(2^n)$.+Se dorește ​o complexitate $T(n) = O(2^n)$.
 </​note>​ </​note>​
  
 <spoiler Hint> <spoiler Hint>
  
-Folositi-va de problema **Combinari**.+Folosiți-vă de problema **Combinari**.
  
 </​spoiler>​ </​spoiler>​
  
 <​note>​ <​note>​
-Solutiile ​se vor genera ​in ordine lexico-grafica!+Soluțiile ​se vor genera ​în ordine lexico-grafica!
  
-Checkerul ​asteapta sa le stocati in aceasta ​ordine.+Checkerul ​așteaptă să le stocați în această ​ordine.
 </​note>​ </​note>​
  
 ==== Problema damelor ==== ==== Problema damelor ====
  
-Problema damelor (sau problema reginelor) ​trateaza ​plasarea a 8 regine de sah pe o tablă de șah de dimensiuni 8 x 8 astfel ​incat sa nu existe ​doua regine care se ameninta ​reciproc. Astfel, se cauta **o solutie** astfel ​incat nicio pereche de doua regine ​sa nu fie pe acelasi rand, pe aceeasi coloana, sau pe aceeasi diagonala. Problema cu opt regine este doar un caz particular pentru problema ​generala, care presupune plasarea a N regine pe o tablă de sah N x N în aceleasi ​conditii. Pentru ​aceasta problema, există ​solutii ​pentru toate numerele naturale N cu excepția lui N = 2 si N = 3.+Problema damelor (sau problema reginelor) ​tratează ​plasarea a 8 regine de sah pe o tablă de șah de dimensiuni 8 x 8 astfel ​încat să nu existe ​două regine care se amenință ​reciproc. Astfel, se caută ​**o soluție** astfel ​încât ​nicio pereche de doua regine ​să nu fie pe același rând, pe aceeași coloană, sau pe aceeași diagonală. Problema cu opt regine este doar un caz particular pentru problema ​generală, care presupune plasarea a N regine pe o tablă de șah N x N în aceleasi ​condiții. Pentru ​această problemă, există ​soluții ​pentru toate numerele naturale N cu excepția lui N = 2 si N = 3.
  
 <spoiler Exemplu 1> <spoiler Exemplu 1>
Line 824: Line 823:
 Fie N = 5 Fie N = 5
  
-Solutie:+Soluție:
  
 |X|-|-|-|-| |X|-|-|-|-|
Line 832: Line 831:
 |-|-|-|X|-| |-|-|-|X|-|
  
-reprezinta ​dama, - reprezinta spatiu ​gol.+reprezintă ​damă, - reprezintă spațiu ​gol.
  
 </​spoiler>​ </​spoiler>​
Line 839: Line 838:
 <spoiler Hint> <spoiler Hint>
  
-E nevoie ​sa facem backtracking pe matrice sau e suficient pe vector?+E nevoie ​să facem backtracking pe matrice sau e suficient pe vector?
  
 </​spoiler>​ </​spoiler>​
Line 846: Line 845:
  
 <​note>​ <​note>​
-Se va cauta singura solutie ​ ​(**oricare** ​solutie corecta), care va fi returnata ​sub format ​unui vector cu $n + 1$ elemente.+Se va caută ​singură soluție ​ ​(**oricare** ​soluție corectă), care va fi returnată ​sub forma unui vector cu $n + 1$ elemente.
  
  
-Solutia ​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.
  
-Elementul 0 este nefolosit, dorim sa pastram conventia ​cu indexare de la 1.+Elementul 0 este nefolosit, dorim să păstrăm convenția ​cu indexare de la 1.
  
 </​note>​ </​note>​
-==== Generare de siruri ​====+==== Generare de șiruri ​====
  
-Vi se da lista de caractere ​si o lista de frecvente ​(pentru caracterul de pe +Vi se dă listă ​de caractere ​și o lista de frecvențe ​(pentru caracterul de pe 
-pozitia ​i, frecventa ​de pe pozitia ​i). Vi se cere sa generati ​toate sirurile +poziția ​i, frecvența ​de pe poziția ​i). Vi se cere să generați ​toate șirurile 
-care se pot forma cu aceste caractere ​si aceste ​frecvente stiind ca nu pot fi +care se pot forma cu aceste caractere ​și aceste ​frecvențe știind că nu pot fi 
-mai mult de K aparitii ​consecutive ale aceluiasi ​caracter.+mai mult de K apariții ​consecutive ale aceluiași ​caracter.
  
 <spoiler Exemplu 1> <spoiler Exemplu 1>
Line 865: Line 864:
 Fie caractere[] = {'​a',​ '​b',​ '​c'​},​ freq[] = {1, 1, 2}, K = 5 Fie caractere[] = {'​a',​ '​b',​ '​c'​},​ freq[] = {1, 1, 2}, K = 5
  
-Solutie:+Soluție:
   * abcc   * abcc
   * acbc   * acbc
Line 890: Line 889:
   * bcbbc   * bcbbc
   * bcbcb   * bcbcb
 +  * bccbb
   * cbbcb   * cbbcb
   * cbcbb   * cbcbb
Line 897: Line 897:
  
 <​note>​ <​note>​
-Solutiile ​se vor genera ​in ordine lexico-grafica!+Soluțiile ​se vor genera ​în ordine lexico-grafica!
  
-Checkerul ​asteapta sa le stocati in aceasta ​ordine.+Checkerul ​așteaptă să le stocați în această ​ordine.
 </​note>​ </​note>​
 ===== Bonus ===== ===== Bonus =====
Line 905: Line 905:
 ==== Problema damelor (AC3) ==== ==== Problema damelor (AC3) ====
  
-**Aplicati ​AC3 pe problema damelor.**+**Aplicați ​AC3 pe problema damelor.**
  
-Algoritmul AC-3 (Arc Consistency Algorithm) este de obicei folosit ​in probleme de satisfacere a constrangerilor ​(CSP). Acesta ​sterge ​arcele din arborele de stari care sigur nu se vor folosi niciodata.+Algoritmul AC-3 (Arc Consistency Algorithm) este de obicei folosit ​în probleme de satisfacere a constrângerilor ​(CSP). Acesta ​șterge ​arcele din arborele de stări ​care sigur nu se vor folosi niciodata.
  
-AC-3 lucreaza ​cu: +AC-3 lucrează ​cu: 
-    * constrangeri+    * constrângeri
     * variabile     * variabile
     * domenii de variabile     * domenii de variabile
  
-variabila ​poate lua orice valoare din domeniul ​sau la orice pas. O constrangere ​este o relatie ​sau o limitare a unor variabile.+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.
  
 === Exemplu AC-3 === === Exemplu AC-3 ===
  
-Consideram ​A, o variabila ​ce are domeniul D(A) = {0, 1, 2, 3, 4, 5, 6} si B o variabila ce are domeniul D(B) = {0, 1, 2, 3, 4}. Cunoastem constrangerile: C1 = "A trebuie ​sa fie impar" ​si C2 = "A + B trebuie ​sa fie egal cu 5".+Considerăm ​A, o variabilă ​ce are domeniul D(A) = {0, 1, 2, 3, 4, 5, 6} și B o variabila ce are domeniul D(B) = {0, 1, 2, 3, 4}. Cunoaștem constrângerile: C1 = "A trebuie ​să fie impar" ​și C2 = "A + B trebuie ​să fie egal cu 5".
  
-Algoritmul AC-3 va elimina ​in primul ​rand toate valorile pare ale lui A pentru a respecta C1 => D(A) = {1, 3, 5}. Apoi, va incerca sa satisfaca ​C2, asa ca va pastra in domeniul lui B toate valorile care adunate cu valori din D(A) pot da 5 => D(B) = {0, 2, 4}.+Algoritmul AC-3 va elimina ​în primul ​rând toate valorile pare ale lui A pentru a respecta C1 => D(A) = {1, 3, 5}. Apoi, va încerca să satisfacă ​C2, așa că va păstra în domeniul lui B toate valorile care adunate cu valori din D(A) pot da 5 => D(B) = {0, 2, 4}.
  
-AC-3 a redus astfel domeniile lui A si B, reducand ​semnificativ timpul folosit de algoritmul backtracking.+AC-3 a redus astfel domeniile lui A si B, reducând ​semnificativ timpul folosit de algoritmul backtracking.
  
 ===== Extra ===== ===== Extra =====
Line 933: Line 933:
 </​spoiler>​ </​spoiler>​
  
-==== Ultimate Tic Tac Toe ==== 
  
-[[http://​theaigames.com/​competitions/​ultimate-tic-tac-toe | The AI Games - Ultimate Tic Tac Toe]] 
  
 +<spoiler Backtracking problems>​
 +Articolul de pe [[https://​leetcode.com/​tag/​backtracking/​| leetcode]] conține o listă cu diverse tipuri de probleme de programare dinamică, din toate categoriile discutate la PA (plus multe altele).
 +</​spoiler>​
 +
 +===== Referințe =====
  
 +[0] Chapter **Backtracking**,​ “Introduction to Algorithms”,​ Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein
pa/laboratoare/laborator-05.1553594475.txt.gz · Last modified: 2019/03/26 12:01 by teodor_mihai.cotet
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