Differences

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

Link to this comparison view

sd-ca:laboratoare:lab-08 [2026/05/11 21:53]
valentin.carauleanu [Aflarea distanţei minime între două noduri]
sd-ca:laboratoare:lab-08 [2026/05/11 22:09] (current)
valentin.carauleanu [Interviu]
Line 4: Line 4:
   * [[stef.dascalu@gmail.com|Ștefan-Teodor Dascălu]]   * [[stef.dascalu@gmail.com|Ștefan-Teodor Dascălu]]
   * [[melih.riza03@gmail.com|Melih Riza]]   * [[melih.riza03@gmail.com|Melih Riza]]
 +  * [[valentin.carauleanu@stud.fim.upb.ro|Cărăuleanu Valentin Gabriel]]
  
 ===== Obiective ===== ===== Obiective =====
Line 106: Line 107:
  
 Pentru a reține distanța și drumul exact de la ''​A''​ la ''​B'',​ se păstrează pentru fiecare nod: Pentru a reține distanța și drumul exact de la ''​A''​ la ''​B'',​ se păstrează pentru fiecare nod:
-  * ''​d[x]'' ​— distanța de la sursă la nodul ''​x''​ +  * ''​d[x]'' ​distanța de la sursă la nodul ''​x''​ 
-  * ''​p[x]'' ​— părintele lui ''​x''​ în drumul de la sursă spre ''​x''​+  * ''​p[x]'' ​părintele lui ''​x''​ în drumul de la sursă spre ''​x''​
  
 În momentul descoperirii unui nod ''​y''​ al cărui părinte este ''​x'',​ se fac atribuirile:​ În momentul descoperirii unui nod ''​y''​ al cărui părinte este ''​x'',​ se fac atribuirile:​
Line 165: Line 166:
 ==== Sortarea topologică ==== ==== Sortarea topologică ====
  
-Se dă un graf orientat aciclic. Orientarea muchiilor corespunde unei relații de ordine de la nodul sursă către cel destinație. O sortare topologică a unui astfel de graf este o ordonare liniară a vârfurilor sale astfel încât, dacă ''​(u,​v)''​ este una dintre muchiile grafului, ''​u'' ​trebuie să apară ​înaintea lui ''​v''​ în înșiruire. Dacă graful ar fi ciclic, nu ar putea exista o astfel de înșiruire (nu se poate stabili o ordine între nodurile care alcătuiesc un ciclu).+Se dă un graf orientat aciclic ​(**DAG** - Directed Acyclic Graph). Orientarea muchiilor corespunde unei relații de ordine de la nodul sursă către cel destinație. O **sortare topologică** a unui astfel de graf este o ordonare liniară a vârfurilor sale astfel încât, dacă ''​(u,​ v)''​ este una dintre muchiile grafului, ''​u'' ​apare înaintea lui ''​v''​ în înșiruire.
  
-Sortarea topologică poate fi văzută și ca plasarea nodurilor de-a lungul unei linii orizontale astfel încât toate muchiile să fie direcționate ​de la stânga la dreapta ​(să nu existe nici o muchie înapoispre părinte).+<note important>​ 
 +Dacă graful este ciclic, sortarea topologică **nu este posibilă**,​ deoarece nu se poate stabili o ordine între nodurile care alcătuiesc un ciclu. 
 +</​note>​ 
 + 
 +Sortarea topologică poate fi vizualizată ca plasarea nodurilor de-a lungul unei linii orizontale astfel încât toate muchiile să fie orientate ​de la stânga la dreapta, fără nicio muchie ​îndreptată ​înapoi spre un părinte. 
 + 
 +=== Algoritm === 
 + 
 +Sortarea topologică se realizează printr-o parcurgere **DFS**, în care se rețin pentru fiecare nod: 
 +  * ''​tDesc[u]''​ - momentul descoperirii nodului ''​u''​ 
 +  * ''​tFin[u]''​ - momentul finalizării procesării nodului ''​u''​ 
 + 
 +La final, nodurile sunt sortate **descrescător** după ''​tFin''​. Nodul care se finalizează cel mai târziu trebuie să apară primul în sortare, deoarece nu depinde de niciun alt nod nedescoperit încă. 
 + 
 +=== Complexitate === 
 + 
 +^ Complexitate ^ Reprezentare prin liste de adiacență ^ Reprezentare prin matrice de adiacență ^ 
 +^ **Timp** ​  | ''​O(|V| + |E|)''​ | ''​O(|V|²)''​ | 
 +^ **Spațiu** | ''​O(|V| + |E|)''​ | ''​O(|V|²)''​ |
  
 === Pseudocod === === Pseudocod ===
Line 182: Line 201:
 contor_timp = 0 contor_timp = 0
  
-// Funcţie de vizitare a nodului+// Funcție de vizitare a nodului
 vizitare(nod) vizitare(nod)
 { {
Line 191: Line 210:
 } }
  
-// Parcurgere în adâncime+// Parcurgere în adâncime ​(recursiv)
 DFS(nod) DFS(nod)
 { {
-    ​stiva s +    ​vizitare(nod) 
-      +    ​pentru fiecare vecin al lui nod
-    viziteaza nod  +
-    s.introdu(nod) +
-    ​ +
-    cât timp stiva s nu este goală+
     {     {
-        ​nodTop = nodul din vârful stivei  +        dacă stare[vecin] == nevizitat
-                +
-        vecin = află primul vecin nevizitat al lui nodTop. +
-        ​dacă vecin există +
-        { +
-            p[v] = nodTop +
-            viziteaza v +
-            s.introdu(v) +
-        }   +
-        altfel+
         {         {
-            ​contor_timp = contor_timp + 1 +            ​p[vecin] = nod 
-            tFin[nodTop] = contor_timp +            ​DFS(vecin)
-            ​s.scoate(nodTop +
         }         }
     }     }
 +    contor_timp = contor_timp + 1
 +    tFin[nod] = contor_timp
 } }
  
Line 222: Line 229:
 pentru fiecare nod u din V pentru fiecare nod u din V
 { {
-    dacă u nu a fost vizitat+    dacă stare[u] == nevizitat
     {     {
-         DFS(u)+        ​DFS(u)
     }     }
 } }
  
-// Sortare ​topologica+// Sortare ​topologică
 sortează nodurile din V descrescător în funcție de tFin[nod] sortează nodurile din V descrescător în funcție de tFin[nod]
 </​code>​ </​code>​
Line 234: Line 241:
 === Exemplu === === Exemplu ===
  
-Profesorul Bumstead își sortează topologic hainele înainte de a se îmbrăca. +Profesorul Bumstead își sortează topologic hainele înainte de a se îmbrăca: 
-  * fiecare ​muchie ''​(u,​ v''​) înseamna ​că obiectul de îmbrăcăminte ''​u''​ trebuie îmbrăcat înaintea obiectului ​de îmbrăcaminte ​''​v''​. Timpii de descoperire ''​(tDesc)''​ și de finalizare ''​(tFin)'' ​obținuți în urma parcurgerii DFS sunt notați lângă ​noduri+  * Fiecare ​muchie ''​(u,​ v)'' ​înseamnă ​că obiectul de îmbrăcăminte ''​u''​ trebuie îmbrăcat înaintea obiectului ''​v''​. Timpii de descoperire ''​tDesc''​ și de finalizare ''​tFin''​ sunt notați lângă ​fiecare nod
-  * același graf, sortat topologic. Nodurile lui sunt aranjate de la stânga la dreapta în ordinea descrescătoare a ''​tFin''​. Observați că toate muchiile sunt orientate de la stânga la dreapta. Acum profesorul Bumstead se poate îmbrăca liniștit+  * Același graf, sortat topologic: nodurile ​sunt aranjate de la stânga la dreapta în ordinea descrescătoare a ''​tFin''​, astfel ​toate muchiile sunt orientate de la stânga la dreapta.
  
-{{sd-ca:​laboratoare:​topologie.jpg}} +{{sd-ca:​laboratoare:​topologie.jpg?500}}
- +
-Așa cum se observă din imagine, sortarea topologică constă în sortarea nodurilor descrescător după timpii de finalizare. Demonstrația acestei afirmații se face simplu, arătând că nodul care se termină mai târziu trebuie să fie efectuat înaintea celorlalte noduri finalizate.+
  
 +Sortarea topologică constă în sortarea nodurilor **descrescător după timpii de finalizare**. Nodul care se finalizează cel mai târziu nu depinde de niciun alt nod rămas, deci trebuie plasat primul în ordine topologică.
 ==== Graf bipartit ==== ==== Graf bipartit ====
  
Line 305: Line 311:
 ==== Ciclu hamiltonian ==== ==== Ciclu hamiltonian ====
  
-Un lanţ hamiltonian într-un graf orientat sau neorientat ''​G = (V, E)''​este o cale ce trece prin fiecare nod din ''​V''​ o singură dată. Dacă nodul de început ​şi cel de sfârşit coincid ​(este vizitat de două ori) vom spune că lanţul formează un **ciclu hamiltonian**.+Un **lanț hamiltonian** într-un graf orientat sau neorientat ''​G = (V, E)''​ este o cale ce trece prin fiecare nod din ''​V''​ o singură dată. Dacă nodul de început ​și cel de sfârșit coincidlanțul formează un **ciclu hamiltonian**.
  
-Un graf ce conţine un ciclu hamiltonian se numeşte graf hamiltonian.+Un graf ce conține un ciclu hamiltonian se numește **graf hamiltonian**. 
 + 
 +<note important>​ 
 +Problema găsirii unui ciclu hamiltonian este **NP-completă**,​ ceea ce înseamnă că nu se cunoaște niciun algoritm eficient (polinomial) pentru cazul general. 
 +</​note>​
  
 === Algoritm === === Algoritm ===
  
-În cadrul acestui laborator, vom folosi metoda backtracking pentru găsirea unui ciclu hamiltonian. ​Pentru contruirea soluţiei, se menţine o listă în care sunt adăugate nodurile parcurse:+În cadrul acestui laborator, vom folosi metoda ​**backtracking** pentru găsirea unui ciclu hamiltonian. ​Se menține o listă în care sunt adăugate nodurile parcurse: 
 + 
 +  * La fiecare pas, se adaugă unul dintre nodurile care nu se află deja în listă. 
 +  * Se construiește recursiv lanțul de ''​lungime_lant + 1''​. 
 +  * Dacă dimensiunea listei este ''​n'',​ se verifică dacă există o muchie de la ultimul nod din listă către primul. Dacă nu există o astfel de muchie, lanțul curent nu poate fi închis într-un ciclu hamiltonian și se continuă cu backtracking. 
 +  * Pentru a afla **toate** ciclurile hamiltoniene,​ la revenirea din apelul recursiv nu se iese din funcție la prima potrivire, ci se încearcă în continuare alte posibilități. 
 + 
 +=== Complexitate ===
  
-  * La fiecare pas, vom adăuga unul dintre nodurile care nu se află deja in listă +^ Complexitate ^ Valoare ^ 
-  Se construieşte recursiv lanţul de lungime_lanţ + 1 +**Timp** ​  ​| ​''​O(|V|!)'' ​în cazul cel mai defavorabil | 
-  ​Dacă dimensiunea listei este ''​n''​ (numărul de noduri din graf), se verifică dacă primul şultimul nod din listă sunt adiacente. În caz contrar, s-a găsit un lanţ hamiltonian,​ dar nu şi un ciclu hamiltonian. +^ **Spațiu** | ''​O(|V|)''​ pentru stiva de recursivitate și lanț |
-  * Pentru a afla toate ciclurile hamiltoniene,​ la revenirea cu succes din apelul recursiv nu se iese din funcţie la găsirea primei potriviri, ci se încearcă în continuare alte posibilităţi.+
  
 === Pseudocod === === Pseudocod ===
Line 322: Line 338:
 <​code>​ <​code>​
 // Inițializări // Inițializări
-număr_noduri ​= număr de noduri din V+numar_noduri ​= număr de noduri din V
  
-// Verifica ​dacă un nod este nou în lanţ +// Verifică ​dacă un nod este nou în lanț 
-nouÎnLanţ(nod, lanţ)+nouInLant(nod, lant)
 { {
-    return !lanţ.conţine(nod)+    return !lant.contine(nod)
 } }
  
-// Construieste ​lanţul hamiltonian +// Construiește ​lanțul hamiltonian 
-construireLanţ(lanţlungime_lanţ)+construireLant(lantlungime_lant)
 { {
-    dacă lungime_lanţ ​== număr_noduri+    dacă lungime_lant ​== numar_noduri
     {     {
-        ​început ​lanţ[0] +        ​inceput ​lant[0] 
-        ​sfârşit ​= ultimul element din lanţ +        ​sfarsit ​= ultimul element din lant 
- +        // Verifică dacă există muchie ​de la sfarsit spre inceput 
-        // Există muchie ​între cele 2 noduri +        dacă muchie(sfarsitinceput)
-        dacă muchie(începutsfârşit)+
         {         {
-            ​// Lanţul este ciclu +            ​afiseaza ​ciclul
-            afişează ​ciclul+
             return true             return true
         }         }
Line 350: Line 364:
         pentru orice nod u din V         pentru orice nod u din V
         {         {
-            ​sfârşit ​= ultimul element din lanţ +            ​sfarsit ​= ultimul element din lant 
-            dacă muchie(u, sfârşitşi nouÎnLanţ(u, lanţ)+            ​// Verifică ​dacă există muchie ​de la sfarsit spre u 
 +            dacă muchie(sfarsitusi nouInLant(u, lant)
             {             {
-                addLast(lanţ, u)    // Adaugă u la lanţ +                addLast(lant, u)       ​// Adaugă u la lanț 
-                 + 
-                ​construireLanţ(lanţlungime_lanţ ​+ 1)+                ​construireLant(lant,​ lungime_lant + 1) 
 +                ​// Pentru afișarea unui singur ciclu hamiltonian,​ 
 +                // linia anterioară se înlocuiește cu: 
 +                // dacă construireLant(lantlungime_lant ​+ 1) == true 
 +                //     ​return true
  
-                ​// Pentru afişarea unui singur ciclu hamiltonian linia anterioară este inlocuită cu: +                removeLast(lant, u)    // Backtrack
-                // dacă construireLanţ(lanţ,​ lungime_lanţ + 1) == true +
-                //       ​return true +
-                 +
-                ​removeLast(lanţ, u) // Backtrack+
             }             }
         }         }
Line 369: Line 384:
  
 // Apelează construirea ciclurilor hamiltoniene // Apelează construirea ciclurilor hamiltoniene
-cicluriHamiltoniene+cicluriHamiltoniene()
 { {
-    // Din moment ce ar trebui să formeze ​un ciclu, lanţul poate incepe ​cu orice nod +    // Din moment ce formează un ciclu, lanțul poate începe ​cu orice nod 
-    ​sursă ​= alegem un nod aleator din V +    ​sursa = alegem un nod aleator din V 
-    addLast(lanţsursă+    addLast(lantsursa
-    ​construireLanţ(lanţ, 1)+    ​construireLant(lant, 1)
 } }
 </​code>​ </​code>​
- 
  
 === Exemplu === === Exemplu ===
  
-{{sd-ca:​laboratoare:​hamilton.png}} +{{sd-ca:​laboratoare:​hamilton.png?400}}
- +
 ===== Exerciții ===== ===== Exerciții =====
  
 <​note>​ <​note>​
-Trebuie să vă creați cont de [[https://​code.devmind.ro/​ | Devmind]], dacă nu v-ați creat deja, pe care îl veți folosi la SD pe toată durata semestrului. ​Aveti grija sa selectati contestul corect la submit, si anume **[[https://​beta.lambdachecker.io/​contest/​34 |SD-CA-LAB-11 Grafuri (Advanced) ]]**+Trebuie să vă creați cont de [[https://​code.devmind.ro/​|Devmind]],​ dacă nu v-ați creat deja, pe care îl veți folosi la SD pe toată durata semestrului.
 </​note>​ </​note>​
  
 1) [**3.5p**] Rezolvați problema **Connected Components**. 1) [**3.5p**] Rezolvați problema **Connected Components**.
 +2) [**3.5p**] Rezolvați problema **Minimum Path**.
 +3) [**3p**] Rezolvați problema **Check Bipartite**.
  
 +===== Interviu =====
  
-2) [**3.5p**] Rezolvați problema **Minimum Path**.+Această secțiune nu este punctată șîncearcă să vă ofere o idee despre tipurile de întrebări pe care le puteți întâlni la un job interview din materia prezentată în cadrul laboratorului.
  
 +=== Probleme recomandate ===
  
-3) [**3p**] Rezolvati problema **Check Bipartite**.+**Sortare topologică:​** 
 +  * [[https://​leetcode.com/​problems/​course-schedule-ii/​description|210. Course Schedule II]] (returnarea ordinii topologice efective) 
 +  ​[[https://​leetcode.com/​problems/​longest-increasing-path-in-a-matrix/​description|329. Longest Increasing Path in a Matrix]] (DAG implicit pe matrice)
  
 +**Componente conexe și grafuri bipartite:​**
 +  * [[https://​leetcode.com/​problems/​is-graph-bipartite/​description|785. Is Graph Bipartite?​]] (verificare bipartitivitate cu BFS/DFS)
 +  * [[https://​leetcode.com/​problems/​accounts-merge/​description|721. Accounts Merge]] (componente conexe cu Union-Find)
 +  * [[https://​leetcode.com/​problems/​satisfiability-of-equality-equations/​description|990. Satisfiability of Equality Equations]] (componente conexe pe graf implicit)
  
 +**Drumuri minime:**
 +  * [[https://​leetcode.com/​problems/​network-delay-time/​description|743. Network Delay Time]] (Dijkstra clasic)
 +  * [[https://​leetcode.com/​problems/​find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance/​description|1334. Find the City with the Smallest Number of Neighbors]] (Floyd-Warshall)
 +  * [[https://​leetcode.com/​problems/​cheapest-flights-within-k-stops/​description|787. Cheapest Flights Within K Stops]] (Bellman-Ford cu constrângeri)
  
 +**Probleme avansate:**
 +  * [[https://​leetcode.com/​problems/​reconstruct-itinerary/​description|332. Reconstruct Itinerary]] (circuit eulerian pe graf orientat)
 +  * [[https://​leetcode.com/​problems/​critical-connections-in-a-network/​description|1192. Critical Connections in a Network]] (punți în graf cu algoritmul Tarjan)
 +  * [[https://​leetcode.com/​problems/​swim-in-rising-water/​description|778. Swim in Rising Water]] (BFS/​Dijkstra pe matrice cu cost variabil)
  
 ===== Bibliografie ===== ===== Bibliografie =====
sd-ca/laboratoare/lab-08.1778525592.txt.gz · Last modified: 2026/05/11 21:53 by valentin.carauleanu
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