Differences

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

Link to this comparison view

pa:laboratoare:laborator-07 [2018/04/12 02:36]
darius.neatu [Exercitii]
pa:laboratoare:laborator-07 [2023/03/15 16:53] (current)
radu.nichita
Line 1: Line 1:
-====== Laborator 07: Parcurgerea ​GrafurilorSortare Topologica ​======+====== Laborator 07: Parcurgerea ​grafurilorAplicații (2/2) ====== 
  
 ===== Obiective laborator ===== ===== Obiective laborator =====
  
-  *Intelegerea conceptului ​de graf si a modurilor de parcurgere aferente +  * Înțelegerea conceptelor ​de graf, reprezentare și parcugere 
-  *Utilitatea si aplicabilitatea sortarii topologice+  * Studierea unor aplicații pentru parcurgeri
  
-===== Importanţă – aplicaţii practice ===== 
  
-Grafurile sunt utile pentru a modela diverse probleme si se regasesc implementati in multiple aplicatii practice:+===== Componente Conexe ​ ===== 
 +>> O **componentă conexă** (**CC**) / **Connected Component** (**CC**) într-un graf **neorientat** este o submulțime maximală de noduri, cu proprietatea că oricare ar fi două noduri x și y din aceasta, există drum de la x la y.
  
-  ​*Retele de calculatoare (ex: stabilirea unei topologii fara bucle) +<spoiler CC - exemplu 01> 
-  *Pagini Web (ex: Google PageRank [1]) +$n = 6$   ​$m = 6$
-  *Retele sociale (ex: calcul centralitate [2]) +
-  *Harti cu drumuri (ex: drum minim) +
-  *Modelare grafica (ex: prefuse [3], graph-cut [4] )+
  
-===== Descrierea problemei și a rezolvărilor =====+$muchii: { (1,2); (1,5); (2,5); (2,3); (3, 5); (4, 6);} $
  
-Graful poate fi modelat drept o pereche de multimi G = (V, E). Multimea V contine nodurile grafului (vertices), iar multimea E contine muchiile (edges), fiecare muchie stabilind o relatie de vecinatate intre doua noduri. O mare varietate de probleme se modeleaza folosind grafuri, iar rezolvarea acestora presupune explorarea spatiului. O parcurgere isi propune sa ia in discutie fiecare nod al grafului, exact o singura data, pornind de la un nod ales, numit in continuare nod sursa. 
  
-Reprezentarea in memorie a grafurilor se face, de obicei, cu liste de adiacenta sau cu matrice de adiacenta. Se pot folosi insa si alte structuri de date, de exemplu un map de perechi < <​sursa,​destinatie>,​cost> ​.+{{pa:​new_pa:​lab08-cc-example01.png}}
  
-Pe parcursul rularii algoritmilor de parcurgereun nod poate avea culori:+Sunt **2 CC**-uri în graful dat: 
 +  * {1, 2, 3, 5} 
 +  * {4, 6}
  
-  *Alb = nedescoperit +Explicație:​ 
-  *Gri = a fost descoperit si este in curs de prcesare +  * Cele 2 sunt mulțimi maximale pentru care se respectă proprietatea ​de conexitate. 
-  *Negru = a fost procesat+  * 4 și 6 nu sunt accesibile din nodurile 1, 2, 3 și 5, prin urmare, acestea trebuie să facă parte din componente diferite.  
 +</​spoiler>​
  
-Se poate face o analogie cu o pata neagra care se extinde pe un spatiu alb. Nodurile gri se afla pe frontiera petei negre. 
-Algoritmii de parcurgere pot fi caracterizati prin completitudine si optimalitate. Un algoritm de explorare complet va descoperi intotdeauna o solutie, daca problema accepta solutie. Un algoritm de explorare optimal va descoperi solutia optima a problemei din perspectiva numarului de pasi care trebuie efectuati. 
  
-==== Parcurgerea in lățime - BFS ====+\\ 
 +>> Un graf **neorientat** este **conex** dacă conține **o singură** componentă conexă. ​
  
-Parcurgerea in latime **(Breadth-first Search - BFS)** este un algoritm de cautare in graf, in care, atunci cand se ajunge intr-un nod oarecare v, nevizitat, se viziteaza toate nodurile nevizitate adiacente lui v, apoi toate varfurile nevizitate adiacente varfurilor adiacente lui v, etc. +<spoiler CC exemplu 02> 
-Atentie! BFS depinde de nodul de start. Plecand dintr-un nod se va parcurge doar componenta conexa din care acesta face parte. Pentru grafuri cu mai multe componente conexe se vor obtine mai multi arbori de acoperire.+$n = 6$   $m = 7$
  
-In urma aplicarii algoritmului BFS asupra fiecarei componente conexe a grafuluise obtine un arbore de acoperire ​(prin eliminarea muchiilor pe care nu le folosim la parcurgere). Pentru a putea reconstitui acest arborese pastreaza pentru fiecare nod dat identitatea parintelui sau. In cazul in care nu exista o functie de cost asociata muchiilorBFS va determina si drumurile minime de la radacina la oricare nod.+$muchii: {(12); (1, 5); (25); (23); (3, 5); (4, 6); (5, 4)} $
  
-Pentru implementarea BFS se foloseste o coada. In momentul adaugarii in coada, un nod trebuie colorat gri (a fost descoperit si urmeaza sa fie prelucrat). 
  
-Algoritmul de explorare BFS este complet si optimal.+{{pa:​new_pa:​lab08-cc-example02.png}}
  
-Algoritm: +Graful dat este conex - există **1 CC**: {1234, 5, 6}.
-<code cpp> +
-BFS(s, G) { +
-    foreach (u ∈ V) { +
-        p(u) = null; // initializari +
-        dist(s,u) = inf; +
-        c(u) = alb;  +
-    } +
-    dist(s) = 0; // distanta pana la sursa este 0 +
-    c(s) = gri; //incepem prelucrarea noduluideci culoarea devine gri +
-    Q = (); //se foloseste o coada cu nodurile de prelucrat +
-    Q = Q + s; // adaugam sursa in coada +
-    while (!empty(Q)) { // cat timp mai am noduri de prelucrat +
-        u = top(Q); // se determina nodul din varful cozii +
-        foreach v ∈ succs(u) { // pentru toti vecinii +
-            if (c(v) = alb) {// nodul nu a fost gasitnu e in coada +
-                // actualizam structura date  +
-                dist(v) = dist(u) + 1; +
-                p(v) = u; +
-                c(v) = gri; +
-                Q = Q + v; +
-            } // close if +
-        } // close foreach +
-        c(u) = negru; //am terminat de prelucrat nodul curent +
-        Q = Q - u; //nodul este eliminat din coada +
-    } //close while +
-} +
-</​code>​+
  
-Complexitate+ExplicațieSe poate ajunge de la oricare nod la oricare altul. 
 +</​spoiler>​
  
-  *cu listaO(|E|+|V|) +<​note>​ 
-  *cu matrice: O(|V|^2)+O componentă conexă reprezintă o partiție a nodurilor în submulțimi! <=> Fiecare nod face parte dintr-o singură componentă conexă! 
 +</​note>​ 
 +==== Algoritmi ==== 
 +=== DFS === 
 +<​note>​ 
 +CC cu DFS
 +  * În algoritmul clasic de parcurgere DFS, de fiecare dată când se găsește un nod fără părinte și se apeleză DFS_RECURSIVE,​ se descoperă o nouă componentă conexă. 
 +      * Toate nodurile vizitate în acel subarbore fac parte din aceeași componentă conexă.  
 +</​note>​
  
-==== Parcurgerea in adancime – DFS ====+== Complexitate ​==
  
-Parcurgerea in adancime **(Depth-First Search - DFS)** porneste de la un nod dat (nod de start), care este marcat ca fiind in curs de procesare. Se alege primul vecin nevizitat al acestui nod, se marcheaza si acesta ca fiind in curs de procesare, apoi si pentru acest vecin se cauta primul vecin nevizitat, si asa mai departe. In momentul in care nodul curent nu mai are vecini nevizitati, se marcheaza ca fiind deja procesat si se revine la nodul anterior. Pentru acest nod se cauta primul vecin nevizitat. Algoritmul se repeta pana cand toate nodurile grafului au fost procesate.+$T = O(n + m)$
  
-In urma aplicarii algoritmului DFS asupra fiecarei componente conexe a grafului, se obtine pentru fiecare dintre acestea cate un arbore ​de acoperire (prin eliminarea muchiilor pe care nu le folosim la parcurgere). Pentru ​a putea reconstitui acest arbore, pastram pentru ​fiecare nod dat identitatea parintelui sau.+=== BFS === 
 +<​note>​ 
 +CC cu BFS: 
 +  * Se parcurge lista de noduri. 
 +      * Pentru fiecare nod care nu are părinte, se pornește o nouă parcurgere BFS din nodul curent. 
 +      * Toate nodurile vizitate într-o parcurgere BFS fac parte din aceeași componentă conexă. 
 +  * Observație:​ Se păstreză lista de părinți de la o parcurgere la alta. 
 +</​note>​
  
-Pentru fiecare nod se vor retine:  +== Complexitate ==
-  *timpul descoperirii +
-  *timpul finalizarii +
-  *parintele +
-  *culoarea+
  
-Algoritmul de explorare DFS nu este nici complet ​(in cazul unei cautari pe un subarbore infinit), nici optimal (nu gaseste nodul cu adancimea minima).+$T = O(n + m)$
  
-Spre deosebire de BFS, pentru ​implementarea DFS se foloseste o stiva (abordare **LIFO** in loc de **FIFO**). Desi se poate face aceasta inlocuire in algoritmul de mai sus, de cele mai multe ori este mai intuitiva folosirea recusivitatii.+<note warning>​ 
 +Deși ambele abordări au aceeași complexitaterecomandăm abordarea cu DFS pentru ​simplitate. 
 +</​note>​
  
-Algoritm:+===== Componente Tare Conexe =====
  
-<code cpp> +>> O **componentă tare conexă** ​(**CTC**) / **Strongly Connected Component** ​(**SCC**într-un graf **orientat** este o submulțime maximală de noduri, cu proprietatea că oricare ar fi două noduri x și y din aceasta, există drum de la la y.
-DFS(G+
-    V = noduri(G) +
-    foreach (u ∈ V) {  +
-        ​// initializare structura date +
-        c(u= alb; +
-        p(u)=null; ​      +
-    } +
-    timp = 0; // retine distanta ​de la radacina pana la nodul curent +
-    foreach (u ∈ V) +
-        if (c(u) = alb) explorare(u);​ // explorez nodul +
-}+
  
-explorare(u) { +<spoiler SCC - exemplu 01> 
-    ​d(u) ​timp++; // timpul de descoperire al nodului u +$n 6$   ​$m ​6$
-    c(u) gri; // nod in curs de explorare +
-    foreach (v ∈ succes(u)) // incerc sa prelucrez vecinii +
-        if (c(v) = alb) { // daca nu au fost prelucrati deja +
-            p(v) = u; +
-            explorare(v);​ +
-        } +
-    c(u) = negru; // am terminat de prelucrat nodul curent +
-    f(u) = timp++; // timpul de finalizare al nodului u +
-+
-</​code>​+
  
-Complexitate:+$arce{(1, 2); (1, 5); (5, 2); (2, 3); (3, 5); (4, 6)} $
  
-  *cu listaO(|E|+|V|) +{{pa:new_pa:lab08-scc-example01.png}}
-  *cu matriceO(|V|^2)+
  
-==== Sortarea Topologica ====+Sunt **4 SCC**-uri în graful dat: 
 +  * {1} 
 +  * {2, 3, 5} 
 +  * {4} 
 +  * {6}
  
-Dandu-se un graf orientat aciclicsortarea topologica realizeaza ​aranjare liniara a nodurilor in functie de muchiile dintre eleOrientarea muchiilor corespunde unei relatii de ordine de la nodul sursa catre cel destinatieAstfel, daca (u,v) este una dintre muchiile grafului, u trebuie sa apara inaintea lui v in insiruire. Daca graful ar fi ciclicnu ar putea exista o astfel de insiruire (nu se poate stabili ​ordine intre nodurile care alcatuiesc ​un ciclu)+Explicație:​ 
 +  * În nodul 1 nu se poate ajungeprin urmare acesta formează ​componentă separatăAnalog pentru 4. 
 +  * Similardin nodul 6 nu se poate ajunge în alt nod, deci și acesta formeză singur ​componentă. 
 +  * Nodurile 2, 3 și 5 formeză ​un ciclu, prin urmare se poate ajunge de la oricare la oricare. 
 +</​spoiler>​
  
-Sortarea topologica poate fi vazuta si ca plasarea nodurilor de-a lungul unei linii orizontale astfel incat toate muchiile sa fie directionate de la stanga la dreapta. 
  
-Exemplu:+\\ 
 +>> Un graf **orientat** este **tare conex** dacă conține o **singură componentă** tare conexă.
  
-Profesorul Bumstead isi sorteaza topologic hainele inainte de a se imbraca.+<spoiler SCC - exemplu 02> 
 +$n = 6$   $m = 6$
  
-{{ :​pa:​laboratoare:​6.1.png?500 |}}+$arce: ​{(1, 2); (1, 5); (5, 2); (2, 3); (3, 5); (4, 6); (4, 1); (5, 4); (6, 5)$
  
 +{{pa:​new_pa:​lab08-scc-example02.png}}
  
-(a) Fiecare muchie (u,v) inseamna ca obiectul de imbracaminte u trebuie imbracat inaintea obiectului de imbracaminte v. Timpii de descoperire d(u) si de finalizare f(u) obtinuti in urma parcurgerii DFS sunt notati langa noduri.+Graful este tare conex - există **1 SCC**: {12, 3, 4, 5, 6};
  
-{{ :pa:​laboratoare:​6.2.png?500 |}} +ExplicațieSe poate vedea că pentru fiecare nod x se poate ajunge în oricare alt nod y. 
 +</​spoiler>​
  
-(b) Acelasi graf, sortat topologic. Nodurile lui sunt aranjate de la stanga la dreapta in ordinea **descrescatoare** ​**timpului de finalizare** f(u). Observati ca toate muchiile sunt orientate de la stanga la dreapta. Acum profesorul Bumstead se poate imbraca linistit.+<​note>​ 
 +O componentă tare conexă reprezintă o partiție ​nodurilor în submulțimi! <=> Fiecare nod face parte dintr-o singură componentă tare conexă! 
 +</​note>​ 
 +==== Algoritmi ==== 
 +=== TARJAN SCC ===
  
-Algoritm:+[[https://​en.wikipedia.org/​wiki/​Tarjan%27s_strongly_connected_components_algorithm|Algoritmul lui Tarjan pentru SCC]] foloseşte o singură parcurgere DFS în urma căreia rezultă o pădure de arbori DFS. Componentele tare conexe vor fi subarbori în această pădure. Rădăcinile acestor subarbori se vor numi **rădăcinile componentelor tare conexe** (**SCC roots**).
  
-Sunt doi algoritmi cunoscuti pentru sortarea topologina.+Nodurile sunt puse pe o stivă, în ordinea vizitării. Când parcurgerea termină de vizitat un subarbore, se determină dacă rădăcina arborelui care s-a terminat de vizitat este și rădăcina unui SCC. Dacă un nod este rădăcina unei componente, atunci el şi toate de deasupra sa din stivă formează acea componentă tare conexă.
  
-Algoritmul bazat pe DFS+Pentru a determina dacă un nod este rădăcina unei componente tare conexe, se definesc
-  ​*parcurgere DFS pentru determinarea timpilor +<code cpp> 
-  ​*sortare descrescatoare in functie de timpul de finalizare+// the timestamp when node was found (when started to visit its subtree) 
 +found[node] = start[node];​
  
-Pentru a evita sortarea nodurilor in functie de timpul de finalizare, se poate folosi o stiva ce retine aceste noduri in ordinea terminarii parcurgerii. +// the minimum accessible timestamp that node can see/access 
- +low_link[node] ​=  ​min found[x] | x is node OR x in ancestors(nodeOR x in descendants(node};
-Un alt algoritm este cel descris de Kahn: +
- +
-<code cpp> +
-TopSort(G) { +
-    V = noduri(G) +
-    L = vida;// lista care va contine elementele sortate +
-    ​// initializare S cu nodurile care nu au in-muchii +
-    ​foreach (u ∈ V) { +
-        if (u nu are in-muchii) +
-     S S + u; +
-    } +
-    while (!empty(S)) { // cat timp mai am noduri de prelucrat +
-        u = random(S); // se scoate un nod din multimea S +
-        L = L + u;  // adaug U la lista finala +
-        foreach v ∈ succs(u) ​// pentru toti vecinii +
-     sterge u-v; // sterge muchia u-v +
-            if (v nu are in-muchii) +
-         S = S + v;  // adauga v la multimea S +
-        } // close foreach +
-    } //close while +
-    if (G are muchii) +
-        print(eroare);  // graf ciclic +
-    else +
-        print(L); // ordinea topologica +
-}+
 </​code>​ </​code>​
  
-Complexitate optimaO(|E|+|V|) +>> **Tarjan SCC****node** is root for a SCC if **low_link[node] ​== found[node]**.
-===== Concluzii si observatii =====+
  
-Grafurile sunt foarte importante pentru reprezentarea si rezolvarea unei multitudini ​de probleme. +<spoiler Explicații found+low_link>​ 
-Cele mai uzuale moduri ​de reprezentare ​unui graf sunt: +**found[node]** reprezintă timpul ​de **start** din DFS, definit în laboratorul anteriorÎn implementare reținem o variabilă **timestamp** care se incrementează ​de fiecare dată când se vizitează un nod. Noua valoare ​lui **timestamp** este **found[node]** (momentul la care **node** a fost găsit).
-  ​*liste de adiacenta +
-  ​*matrice de adiacenta+
  
-Cele doua moduri uzuale ​de parcurgere neinformata a unui graf sunt+**low_link[node]** reprezintă cel mai mic timp de descoperire al unui nod **x** la care se poate ajunge pornind din **node** și mergând pe arcele/​muchii nevizitate (se poate coborî sau urca). Practic, nodul cu cel mai mic timp de descoperire care se poate atinge prin traversarea a 0 sau mai multe arce.  
-  *BFS – parcurgere ​in latime +   * observații prelimilare
-  *DFS – parcurgere ​in adancime+    * nodurile vizitate înaintea lui **node** au valoare **found** mai mică (deci și orice strămoș a lui **node** - mulțimea **ancestors(node)**) 
 +    * nodurile descendente ale lui **node** au valoare **found** mai mare (mulțimea **descendants(node)**) 
 +    * întrucât și **node** face parte din subarbore, inițializăm **low_link[node] = found[node]**. Valoarea finală va fi mai mică sau egală decât aceasta (conform definiției,​ vom căuta un minim). 
 +    
 +   * după ce **toate** nodurile accesibile din **node** au fost vizitate, se cunoaște ***valoarea finală** a lui  **low_link[node]** și putem avea 2 cazuri: 
 +    * **low_link[node] == found[node]** 
 +       * dacă valoarea finală a rămăs cea inițială, înseamnă că **NU** s-a urcat în arbore (altfel am fi întâlnit valori mai mici decât cea inițială) 
 +       * prin urmare **node** este rădăcina unui SCC (primul nod întâlnit din acest SCC) 
 +       * nodurile din vârful stivei de deasupra lui **node** formează SCC-ul găsit 
 +    * **low_link[node] < found[node] ** 
 +       * dacă valoarea finală pentru **low_link[node]** este mai mică decât cea inițială, înseamnă că s-a urcat în arbore 
 +       * în acest caz există cel puțin o muchie **(y, x)** unde **x** este strămoș și **y** este descendent pentru **node**, prin care **y** (si implicit și **node**) își actualizează minimul cu valoarea din **x** 
 +       ​drumul **x - ... - node -... y - ... - x ** este atunci un ciclu care face parte dintr-un SCC; **node** este un nod oarecare dintr-un astfel de ciclu ("la mijloc",​ întrucât mai sus de el există cel puțin un nod mai aproape de "​începutul ciclului",​ adică nodul **x**) 
 +       * prin urmare, suntem siguri că **node** nu este rădăcina unui SCC  
 +</​spoiler>​
  
-Sortarea topologica este o modalitate de aranjare a nodurilor in functie de muchiile dintre ele. In functie de nodul de start al DFS, se pot obtine sortari diferitepastrand insa proprietatile generale ale sortarii topologice.+== Algoritm == 
 +<code cpp | TARJAN_SCC>​ 
 +// Tarjan_SCC 
 +// * visit all nodes with DFS 
 +//      * compute found[node] and low_link[node] 
 +//      * extract SCCs 
 +// 
 +// nodes     = list of all nodes from G 
 +// adj[node] = the adjacency list of node 
 +//             ​example:​ adj[node] = {...neigh, ...} => edge (node, neigh) 
 +TARJAN_SCC(G = (nodes, adj)) { 
 +    // STEP 1: initialize results 
 +    // parent[node] = parent of node in the DFS traversal 
 +    // 
 +    // the timestamp when node was found (when started to visit its subtree) 
 +    // Note: The global timestamp is incremented everytime a node is found. 
 +    // 
 +    // the minimum accessible timestamp that node can see/​access 
 +    // low_link[node] =  min { found[x] | x is node OR x in ancestors(node) OR x in descendants(node) }; 
 +    // 
 +    foreach (node in nodes) { 
 +        parent[node] = null; // parent not yet found 
 +        found[node] = +oo; // node not yet found 
 +        low_link[node] = +oo; // value not yet computed 
 +    } 
 +    nodes_stack = {}; // visiting order stack
  
-===== Exercitii ===== +    // STEP 2: visit all nodes 
-<​note>​ +    timestamp ​0; // global timestamp 
-In acest laborator vom folosi scheletul de laborator din arhiva {{pa:​new_pa:​skel-lab07.zip}}. +    ​foreach (node in nodes) { 
-</note>+        if (parent[node] == null) // node not visited 
 +            ​parent[node] = node; // convention: the parent of the root is actually the root
  
-<note warning> +            // STEP 3: start a new DFS traversal this subtree 
-Pentru tot restul semestrului,​ vom face conventia ca nodurile sunt indexate de la 1 (123...n).+            DFS(nodeadjparenttimestampfound, low_link, nodes_stack)
 +        } 
 +    } 
 +}
  
-numar de noduri+DFS(node, adj, parent, ref timestamp, found, low_link, nodes_stack) { 
 +    // STEP 1: a new node is visited - increment the timestamp 
 +    found[node] ​++timestamp;​ // the timestamp when node was found 
 +    low_link[node] = found[node];​ // node only knows its timestamp 
 +    nodes_stack.push(node);​ // add node to the visiting stack
  
-numar de muchii+    // STEP 2: visit each neighbour 
 +    foreach (neigh in adj[node]) { 
 +        // STEP 3: check if neigh is already visited 
 +        if (parent[neigh] !null) { 
 +            // STEP 3.1: update low_link[node] with information gained through neigh 
 +            // note: neigh is in the same SCC with node only if it's in the visiting stack; 
 +            // otherwise, neigh is from other SCC, so it should be ignored 
 +            if (neigh in nodes_stack) { 
 +                low_link[node] = min(low_link[node],​ found[neigh]);​ 
 +            }
  
-adj[node] = lista de adiacenta a nodului node +            continue; 
-</​note>​+        }
  
-<​note>​+        // STEP 4: save parent 
 +        parent[neigh] = node;
  
-Un tool care poate fi folosit pentru a desena grafuri se gaseste pe [[https://csacademy.com/​app/​graph_editor/​|csacademy]]. +        ​// STEP 5: recursively visit the child subtree 
-</​note>​+        ​DFS(neigh,​ adj, parent, timestamp, found, low_link, nodes_stack);​
  
-=== BFS === +        // STEP 6: update low_link[node] with information gained through neigh 
-Se da un graf **neorientat** cu **n** noduri si **m** muchii. Se mai da un nod special **source**, pe care il vom numi sursa. ​+        low_link[node] ​min(low_link[node],​ low_link[neigh]);​ 
 +    }
  
-Se cere sa se gaseasca **numarul minim de muchii** ce trebuie parcurse de la **source** la **toate ** celelalte noduri+    // STEP 7: node is root in a SCC if low_link[node] == found[node] 
 +    // (there is no edge from a descendant to an ancestor) 
 +    if (low_link[node] == found[node]) { 
 +        // STEP 7.1: pop all elements above node from stack => extract the SCC where node is root 
 +        new_scc = {}; 
 +        do { 
 +            x = nodes_stack.pop();​ 
 +            new_scc.push(x);​ 
 +        } while (x != node); // stop when node was popped from the stack
  
-<note warning>​ +        // STEP 7.2save / print the new SCC 
-Restrictii si precizari+        ​print(new_scc);​ 
-  * $ n, m <= 10^5 $ +    } 
-</​note>​+}
  
-<note> +</code>
-Rezultatul se va returna sub forma unui vector **d** cu ** n ** elemente.+
  
-Conventie+Observații
-  * ** d[node] ** = numarul minim de muchii ce trebuie parcurse de la **source** la nodul **node** +  * La pasul **3.1** se încearcă actualizarea lui **low_link[node]** ​cu informația din **neigh** doar dacă **neigh** este în stivă. 
-  * ** d[source] = ** +    * Nodul **neigh** are deja părinte, deci poate fi în unul din următoare 2 cazuri: 
-  * ** d[node] = -1**, daca nu se poate ajunge de la **source** la **node** +      * **neigh** este în curs de vizitare (deci este în stivă) => **neigh** este strămoș a lui **node** 
-</​note>​+        Reactualizăm ​**low_link[node]** cu valoarea din **neigh**. 
 +      * **neigh** este deja vizitat (deci a fost scos din stivă) ​=**neigh** face parte din alt subarbore, terminat anterior. 
 +        * Prin urmare, anterior s-a stabilit că **neigh** face parte dintr-un alt SCC și trebuie ignorat (întrucât sigur are valoare **found** mai mică decât a lui **node*și ar reactualiza ​**low_link[node]** în mod eronat.  
 +    * Se face această actualizare doar dacă **neigh** este strămoș al lui  
 +== Complexitate == 
 +  ​* **complexitate temporală ​**: $T = O(n + m)$ 
 +  ​* **complexitate spațială ​** : $S = O(n)$ 
 +    * recursivitate +  câteva structuri de date de lungime $O(n)$
  
-<spoiler Exemplu 1> +=== Kosaraju === 
-$n 5$   ​$m ​4$  $source ​3$ +Există și alt algoritm pentru determinarea componentelor tare conexe. Algoritmul lui Kosaraju se bazează pe compactarea ciclurilor. Deoarece are aceeași complexitate ca și Tarjan, nu îl vom studia la laborator la PA. Am ales algoritmul lui Tarjan întrucât îl putem modifica ușor pentru a produce și alte rezultate.
  
-$muchii{ (1,2); (1,3); (2,3); (2,4);} $+Puteți consulta următoarele materiale dacă doriți să aflați mai multe 
 +  * https://​www.youtube.com/​watch?​v=RpgcYiky7uw 
 +  * https://​iq.opengenus.org/​kosarajus-algorithm-for-strongly-connected-components/​ 
 +===== Puncte de articulație =====
  
 +>> **Punct de articulație** ​ / **nod critic** / **Cut Vertex** (**CV**) este un nod într-un graf **neorientat** a cărui eliminare duce la creșterea numărului de componente conexe (CC) - se elimină nodul împreună cu muchiile incidente.
  
-Raspuns: +<spoiler CV - exemplu 01> 
-|node|1|2|3|4|5| +$n = 8$   $m = 6$
-|d|1|1|0|2|-1|+
  
-Explicatie +$muchii{(1, 2); (2, 3); (3, 4); (4, 1); (1, 5); (5, 6); (6, 7); (7, 5); (7, 8)} $
-Graful dat este cel din figura urmatoare.+
  
-{{pa:laboratoare:lab07-bfs-graph1.png}}+{{pa:new_pa:lab08-cv-example01.png}}
  
-  ​* ** d[3] = 0 ** pentru ca este sursa +Sunt **3 CV**-uri în graful dat: 1, 5 și 7. 
-  * ** d[1] = d[2] = 1 ** pentru ca exista muchie directa de la la fiecare nod + 
-  * ** d[4] = ** pentru ca trebuie sa parcurgem 2 muchii ($3-2-4$) +Explicație:​ 
-  * ** d[5] = -1 ** pentru ca nu se poate ajunge de la la 5+  * Dacă ștergem nodul 1, graful se sparge în CC-uri: {2, 3, 4}, {5, 6, 7, 8}. 
 +  * Dacă ștergem nodul 5, graful se sparge în CC-uri: {1, 2, 3, 4}, {6, 7, 8}. 
 +  * Dacă ștergem nodul 7, graful se sparge în 2 CC-uri: {1, 2, 3, 4, 5, 6}, {8}. 
 +  * Dacă ștergem oricare alt nod, ,graful rămâne conex.
 </​spoiler>​ </​spoiler>​
  
 +==== TARJAN CV ====
 +Putem modifica ușor algoritmul TARJAN SCC astfel încât să obținem [[https://​en.wikipedia.org/​wiki/​Biconnected_component | Algoritmul lui Tarjan pentru CV]].
  
-<spoiler Exemplu 2> +În mod analog, pentru a determina dacă un nod este CV, se definesc și folosesc **found** și **low_link**.
-$n = 7$   $m = 7$  $source = 1$ +
  
-$muchii{ (1,2); (1,4)(2,3); (4,5); (5,6); (3,7); (7,6) } $+>> **TARJAN CV****node** is **CV** if 
 +>>**i)** node is NOT root and **low_link[neigh] >= found[node]** for at least one **neigh** in **adj[node]** 
 +>> ​ OR 
 +>> **ii)** node is root and children(node> 1
  
-Raspuns: +Dacă **node** este rădăcină într-un subarbore, acesta are valoarea **found** mai mică decât a oricărui nod. Prin urmare, condiția **low_link[neigh] >= found[node]** ar fi adevărată mereu și nu ne-ar putea furniza o informație utilă. De aceea, cazul **i)** nu este aplicabil pentru rădăcină. Putem trata foarte simplu cazul pentru rădăcină folosind **ii)**dacă **node** este rădăcină a unui subarborele și are cel puțin ​copii, atunci, prin eliminarea lui **node**, arborele acestuia se sparge într-un număr de subarbori egal cu numărul de copii.
-|node|1|2|3|4|5|6|7| +
-|d|0|1|2|1|2|3|3|+
  
-Explicatie: ​ +<spoiler Explicații found+low_link>​ 
-Graful dat este cel din figura urmatoare.+**found[node]** are aceeași semnificație ca la SCC.
  
-{{pa:laboratoare:lab07-bfs-graph2.png}}+**low_link[node]** are aceeași semnificație ca la SCC.  
 +   * observații/​diferențe: 
 +    * Nu este nevoie de folosirea stivei de vizitare. 
 +      * La SCC aveam nevoie de stiva de noduri pentru a nu folosi o muchie **node -> neigh** (arc) care unea 2 SCC-uri. 
 +      * Într-un graf neorientat nu putem avea o muchie care să unească 2 subarbori, deoarece în momentul în care un capăt este vizitat, adaugă și celălalt capăt în același subarbore. 
 +    * **neigh** este copil al lui **node** în parcurgerea DFS => **found[neigh] > found[node]** 
 +   * după ce un copil **neigh** este vizitat, se cunoaște ***valoarea finală** a lui  **low_link[neigh]** și putem avea 2 cazuri: 
 +    * **low_link[neigh] < found[node] ** 
 +       * inițial **low_link[neigh] = found[neigh]**,​ deci **low_link[neigh] > found[node]** 
 +       * în acest caz există cel puțin o muchie **(y, x)** unde **x** este strămoș ​ și **y** este descendent pentru **node** prin care **y** (și implicit și **node**) își actualizează minimul cu valoarea din **x** 
 +       * drumul **x ... - node - neigh - ... y - x ** este atunci un ciclu 
 +         * dacă **node** este eliminat din graf, toate nodurile din subarborele lui **neigh** vor rămâne conectate de restul grafului prin muchia **(y, x)** 
 +         * deci nu putem trage vreo concluzie doar analizând vecinul curent **neigh**, trecem la următorul 
 +    * **low_link[neigh] >= found[node] ** 
 +      * în acest caz nu există ciclul **x - ... - node - neigh - ... y - x ** de la cazul anterior 
 +      * eliminarea lui **node** ar duce la separarea subarborelui lui **neigh** de restul grafului 
 +      * prin urmare, numărul de componente conexe crește cu cel puțin 1, deci **node** este sigur un **CV** (concluzie corectă chiar dacă ne-am uitat la un singur vecin **neigh**)
  
-  * ** d[1] = 0 ** pentru ca 1 este sursa 
-  * ** d[2] = d[4] = 1 ** pentru ca exista muchie directa de la 2 la fiecare nod 
-  * ** d[3] = d[5] = 2 ** pentru ca trebuie sa parcurgem 2 muchii ($1-2-3$, $1-4-5$) 
-  * ** d[6] = d[7] = 3 ** pentru ca trebuie sa parcurgem 3 muchii ($1-2-3-7$ sau $1-4-5-6$) 
 </​spoiler>​ </​spoiler>​
  
 +\\
 +\\
 +Punem la dispoziție un diff de pseudocod: [[https://​pastebin.com/​raw/​8th3Pnjg | TARJAN_SCC vs TARJAN_CV]]. Se observă că este același algoritm, singurele diferențe relevante sunt:
 +  * STEP **3.1**: condiția după care se reactulizează **low_link[node]** în funcție de **neigh** atunci când cel din urmă este deja vizitat
 +  * STEP **7**: condiția prin care se determină dacă **node** este o rădăcină de SCC / CV.
 +\\
  
-<spoiler Exemplu 3> +== Complexitate == 
-$7$   $= 8$  $source ​1+  * **complexitate temporală **: $O(n + m)$ 
 +  * **complexitate spațială ** : $O(n)$ 
 +    * recursivitate +  câteva tablouri auxiliare de lungime n 
 +===== Punți / muchii critice ===== 
 +>> **Punte** ​ / **muchie critică** / **Critical Edge** (**CE**) este o muchie într-un graf **neorientat** a cărei eliminare duce la creșterea numărului de  componente conexe (CC) - se elimină muchia, fără a se sterge capetele (nodurile) acesteia.
  
-$muchii: { (1,2); (1,4); (2,3); (4,5); (5,6); (3,7); (7,6); (1, 6) } $+<spoiler CE - exemplu 01> 
 +$n = 8$   $m = 6$
  
-Raspuns: +$muchii{ (1,2); (2, 3); (34); (4, 1); (1, 5); (5, 6); (67); (7, 5); (7, 8)} $
-|node|1|2|3|4|5|6|7+
-|d|0|1|2|1|2|1|2|+
  
-Explicatie +{{pa:new_pa:​lab08-ce-example01.png}}
-Graful dat este cel din figura urmatoare.+
  
-{{pa:laboratoare:​lab07-bfs-graph3.png}}+Sunt **2 CE**-uri în graful dat(1, 5) și (7,8)
  
-  * ** d[1] = 0 ** pentru ca 1 este sursa +Explicație:​ 
-  * ** d[2] = d[4] = d[6] = ** pentru ca exista muchie directa de la la fiecare nod +  * Dacă ștergem muchia (1, 5), graful se sparte în CC-uri: {123, 4}, {5, 6, 7, 8}. 
-  * ** d[3] = d[5] = d[7] = 2 ** pentru ca trebuie sa parcurgem 2 muchii ​($1-2-3$$1-4-5$$1-6-7$)+  ​Dacă ștergem muchia ​(7, 8), graful se sparte în CC-uri: {1, 2, 3, 45, 67}, {8}. 
 +  * Dacă ștergem oricare altă muchie, graful rămâne conex.
 </​spoiler>​ </​spoiler>​
  
 +==== TARJAN CE ====
 +Se modifică algoritmul de CV. Se folosesc aceleași definiții și semnificații pentru **found** și **low_link**.
  
-=== TOPOLOGICAL SORT === +>> ​**TARJAN CE****(node, neigh)** is a **CE** if **low_link[neigh] > found[node]** where **neigh** in **adj[node]**.
-Se da un graf **orientat** aciclic cu **n** noduri si **m** arce. Se cere sa se gaseaca ​**o sortare topologica** valida.+
  
-<note warning> 
-Restrictii si precizari: 
-  * $ n, m <= 10^5 $ 
-</​note>​ 
  
-<note+<spoiler Explicație
-Rezultatul se va returna sub forma unui vector ​**topsort** cu ** ** elemente.+Există 2 tipuri de muchii în parcugerea DFS într-un graf neorientat:​ 
 +  ​* **(node, neigh)**: muchiile din arbore (numită și muchie de arbore) 
 +  * **(y, x)**: muchie de la un nod **y** la un strămoș **x** (numită și muchie înapoi) 
 +Tipul al 2-lea de muchie închide un ciclu, deci clar nu reprezintă un CE. Prin urmare trebuie să căutăm toate CE-urile printre muchiile ​**(node, neigh)** din arbore.
  
-Vectorul ​**topsort** va reprezenta o permutare ​multimii ${123,...n}$ reprezentand sortarea topologica gasita. +Când se termină de vizitat subarborele lui **neigh** și cunoaștem valoarea finală ​lui **low_link[neigh]** putem avea: 
-</note+  * **low_link[neigh] <= found[node]**:​  
- +    * analog explicațiilor de la CVdin subarborele lui **neigh** se poate urca până la un nod **x** (x este **node** SAU un strămoș al lui **node**) => muchia **(nodeneigh)** face parte dintr-un ciclu 
-<​spoiler ​Exemplu 1> +    * prin urmaredacă se taie aceastatoate nodurilor de pe ciclu rămân conectate, deci nu este CE 
-$n = 5$   $m = 4$ +  * **low_link[neigh] ​found[node]**:​ 
 +    * înseamnă că nu există acel ciclu de la pasul anterior (nu s-a putut urca în arbore mai sus de **node**) 
 +    * prin urmare, **(node, neigh)** este **CE** 
 +</spoiler>
  
-$arce(1,2)(1,3); (2,​3); ​(2,4);} $+== Complexitate == 
 +  * **complexitate temporală **$T = O(n + m)
 +  * **complexitate spațială ** : $S = O(n)
 +    * recursivitate +  câteva structuri de date de lungime $O(n)$ 
 +===== Componente Biconexe =====
  
 +>> O **componentă biconexă** / **BiConnected Component** (**BCC**) într-un graf **neorientat** este o submulțime maximală de noduri cu proprietarea că nu conține puncte de articulație - oricare nod s-ar elimina, nodurile rămase sunt încă conectate.
  
-Raspuns: ​$topsort ​[1, 2, 3, 4, 5] $+<spoiler BCC - exemplu 01> 
 +$8$   $m = 9$
  
-Explicatie +$muchii{(1, 2); (2, 3); (3, 4); (4, 1); (1, 5); (5, 6); (6, 7); (7, 5); (7, 8)} $
-Graful dat este cel din figura urmatoare.+
  
-{{pa:laboratoare:lab07-topsort-graph1.png}} +{{pa:new_pa:lab08-bcc-example01.png}}
-  * deoarece avem arcele $1 \rightarrow 3$ si $1 \rightarrow 2$, 1 trebuie sa apara inainte lui 2 si 3 +
-  * deoarece avem arcul $2 \rightarrow 3$ si $2 \rightarrow 4$, 2 trebuie sa apara inainte lui 3 si 4 +
-  * 5 nu depinde de nimeni, poate sa apara oriunde+
  
-Toate sortarile topologice valide sunt: +Sunt **4 BCC**-uri în graful dat:  
-  ​cele date de ordinea relativa a primelor 4 noduri: 1,2,3,4) +{1, 2, 3, 4} 
-    ​$topsort = [1, 2, 3, 4, 5] $ +{1, 5} 
-    ​$topsort = [1, 2, 3, 5, 4] $ +{5, 67} 
-    ​$topsort = [1, 2, 5, 3, 4] $ +{78}
-    * $topsort = [1, 5, 2, 3, 4] $ +
-    * $topsort = [5, 1, 2, 3, 4] $ +
-  * cele date de ordinea relativa a primelor 4 noduri(1,2,4,3) +
-    $topsort = [1, 2, 4, 3, 5] $ +
-    * $topsort = [1, 2, 4, 5, 3] $ +
-    $topsort = [1, 2, 5, 4, 3] $ +
-    $topsort = [1, 5, 24, 3] $ +
-    $topsort = [51, 2, 4, 3] $+
  
 +Explicație:​
 +  * Dacă ștergem muchia (1, 5), graful se sparge în 2 CC-uri: {1, 2, 3, 4}, {5, 6, 7, 8}.
 +  * Dacă ștergem muchia (7, 8), graful se sparge în 2 CC-uri: {1, 2, 3, 4, 5, 6, 7}, {8}.
 +  * Dacă ștergem oricare altă muchie, graful rămâne conex.
 </​spoiler>​ </​spoiler>​
  
  
-<spoiler Exemplu 2> +\\ 
-$n = 9$   $m = 8$ +>> Un graf **neorientat** este **biconex** dacă nu conține puncte de articulație - conține o singură componentă biconexă.
  
-$arce: {  +<spoiler BCC - exemplu 02> 
-(1,2); +$n = 8$   $m = 10$
-(1,3); +
-(3,4); +
-(3,5); +
-(5,9); +
-(4,6); +
-(4,7); +
-(4,8); +
-$+
  
 +$muchii: {(1, 2); (2, 3); (3, 4); (4, 1); (1, 5); (5, 6); (6, 7); (7, 5); (7, 8); (8, 2)} $
  
-Raspuns$topsort = [1, 2, 3, 4, 6, 7, 8, 5, 9] $+{{pa:new_pa:​lab08-bcc-example02.png}}
  
-Explicatie:  +Sunt **1 BCC**-uri în graful ​dat: {1, 2, 3, 4, 5, 6, 7, 8}
-Graful ​dat este cel din figura urmatoare.+
  
-{{pa:laboratoare:​lab07-topsort-graph2.png}} +Explicație
- +  * Nu există noduri/​puncte critice în graf (se poate șterge orice nod și graful rămâne conex).
-Se observa din desen ca solutia mentionata este valida.+
 </​spoiler>​ </​spoiler>​
  
-=== BONUS === +<note warning>​ 
-Se da un tablou bidimensional ​de dimensiune ​**n x n**. Fiecare celula este o camera.+Împărțirea în componente biconexe a unui graf neorientat reprezintă **o partiție disjunctă a muchiilor grafului** (împreună cu vârfurile adiacente muchiilor). Acest lucru implică faptul că unele vârfuri pot face parte din mai multe componente biconexe diferite (vezi BCC - exemplu 01) - mai exact, punctele de articulație vor face parte din mai multe componente. 
 +</​note>​ 
 +==== TARJAN BCC ==== 
 +Se modifică algoritmul ​de CV. Se folosesc aceleași definiții și semnificații pentru ​**found** și **low_link**.
  
-O valoare din matrice poate sa fie **0**, **1** sau **2**. +  ​Se folosește o stivă ​**edges_stack** în care se adaugă toate muchiile **(nodeneigh)** atunci când se înaintează în recursivitate.  
-  * celula libera +  ​Atunci când se termină de vizitat un copil **neigh**, dacă se îndeplinește condiția de **CV** (**low_link[neigh] >= found[node]**),​ înseamnă că prin eliminarea lui **node** tot subarborele **node - neigh - ...** rămâne deconectat. Prin urmare, toate muchiile din stivă de deasupra muchiei **(node, neigh)** ​ (inclusiv) formează o componentă biconexă (mulțimea de noduri formată din capetele acestor muchii)
-  * celula blocata ​(contine un obstacol - nu se poate intra intr-o astfel de camera+  * Se termină de vizitat copilul curent și se trece la următorul. De fiecare dată când se găsește un copil **neigh** cu **low_link[neigh] >= found[node]** se formează o nouă **BCC**. 
-  * celula contine o poarta ​de teleportare ​(ex. iesire catre exterior - cine stie ce o fi afara+ 
-  +== Complexitate =
-Un student ​de la Poli se afla intr-un punct interior dat prin coodonatele ​**start_row** si **start_col**. Deoarece studentul este dornit sa termine facultatea cat mai repede, se intreaba care este **lungimea celui mai scurt drum** de  +  * **complexitate temporală **: $T O(n + m)$ 
-la pozitia sa catre o poarta ​de teleportare.+  * **complexitate spațială ** : $S O(n + m)$ 
 +    * recursivitate + câteva structuri ​de date de lungime $O(n)$ / $O(m)$ 
 +      * ATENȚIE! În plus, față ​de CE/CV , se stochează o stivă de muchii. 
 + 
 + 
 +===== Importanţă – aplicaţii practice ===== 
 +  * SCC: Data Mining, Compilatoare,​ problema 2-SAT. 
 +  * BCC: cele mai importante aplicații se găsesc în rețelele de calculatoare,​ deoarece ​un BCC asigură redundanţă (există cel puțin 2 căi de a conecta o entitate la celelalte). 
 +   
 +===== TLDR ===== 
 + 
 +  ​Se poate folosi/​modifica algoritmul lui Tarjan pentru a determina ​**SCC****CV** **CE** / **BCC**. 
 +  * Deoarece algoritmul se folosește ​de o parcurgere DFS, complexitatea este liniară în toate cazurile. 
 + 
 +===== Exercitii =====
 <​note>​ <​note>​
-Studentul ​se poate deplasa doar pe verticala sau pe orizontala.+Scheletul de laborator ​se găsește ​pe pagina [[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​skel/​lab08|pa-lab::​skel/​lab08]].
 </​note>​ </​note>​
  
 +<note warning>
 +Înainte de a rezolva exercițiile,​ asigurați-vă că ați citit și înțeles toate precizările din secțiunea
 +[[https://​ocw.cs.pub.ro/​courses/​pa/​skel_graph | Precizari laboratoare 07-12]].
  
-Task-uri+Prin citirea acestor precizări vă asigurați că
-  gasiti ​**lungimea** ceruta +   ​știți ​**convențiile** folosite 
-  reconstituiti ​**drumul** de lungime minima (daca sunt mai multe, se poate afisa oricare)+   ​evitați ​**buguri** 
 +   * evitați **depunctări** la lab/​teme/​test
  
 +</​note>​
 +
 +=== SCC ===
 +Se dă un graf **orientat** cu **n** noduri și **m** arce. Să se găsească **componentele tare-conexe** folosind algoritmul lui **Tarjan**. Secțiunea de teorie conține exemple grafice explicate.
  
 <note warning> <note warning>
-Restrictii si precizari+Restricții și precizări
-  * $ n <= 10^$+  * $ n <= 10^$ 
 +  * $ m <= 2 * 10^5 $ 
 +  * timp de execuție 
 +    * C++: 1s 
 +    * Java: 4s
 </​note>​ </​note>​
  
  
 +=== CV ===
 +Se dă un graf **neorientat conex** cu **n** noduri și **m** muchii. Se cere să se găsească toate **punctele critice** folosind algoritmul lui **Tarjan**. Secțiunea de teorie conține exemple grafice explicate.
  
-<spoiler Exemplu+<note warning
-$n = 5$+Restricții și precizări:​ 
 +  * $ n <10^5 $ 
 +  * $ m <= 2 * 10^5 $ 
 +  * timp de execuție 
 +    * C++: 1s 
 +    * Java: 4s 
 +</​note>​
  
  
-|1|0|2|1|0| +=== CE === 
-|0|0|0|1|1|  +Se dă un graf **neorientat conex** cu **n** noduri și **m** muchii. Se cere să se găsească toate **muchiile critice** folosind algoritmul lui **Tarjan**. Secțiunea de teorie conține exemple grafice explicate.
-|2|1|0|0|1| ​  +
-|1|1|0|1|0| ​   +
-|0|1|2|1|0|+
  
 +<note warning>
 +Restricții și precizări:
 +  * $ n <= 10^5 $
 +  * $ m <= 2 * 10^5 $
 +  * timp de execuție
 +    * C++: 1s
 +    * Java: 4s
 +</​note>​
  
-Raspuns: +=== BCC === 
-$ lungime ​3 $+Se dă un graf **neorientat conex** cu **n** noduri și **m** muchii. Se cere să se găsească toate **componentele biconexe** folosind algoritmul lui **Tarjan**. Secțiunea de teorie conține exemple grafice explicate.
  
-$drum (3, 4) \rightarrow (3, 3) \rightarrow (2, 3) \rightarrow (1, 3) $+<note warning>​ 
 +Restricții și precizări:​ 
 +  * n <= 10^5 $ 
 +  * $ m <= 2 * 10^5 $ 
 +  * timp de execuție 
 +    * C++: 1s 
 +    * Java: 4s 
 +</​note>​
  
-Explicatie: Exista doua posibilitati de a porni din punctul de coordonate $(3, 4)$ si a ajunge printr-un drum de lungime minima la o poarta. Unul dintre acestea urmeaza traseul mentionat. ​ 
-</​spoiler>​ 
  
 === Extra === === Extra ===
-<​spoiler ​muzeu+<​spoiler ​rețele
-Rezolvati ​problema [[https://​infoarena.ro/​problema/​muzeu +Rezolvați ​problema [[https://​infoarena.ro/​problema/​reteleretele]] pe infoarena.
-muzeu]] pe infoarena.+
 </​spoiler>​ </​spoiler>​
  
-<​spoiler ​arbore3+<​spoiler ​clepsidra
-Rezolvati ​problema [[https://​infoarena.ro/​problema/​arbore3 +Rezolvați ​problema [[https://​infoarena.ro/​problema/​clepsidraclepsidra]] pe infoarena.
-arbore3]] pe infoarena. ​+
 </​spoiler>​ </​spoiler>​
  
-<spoiler Pokemon GO AWAY> 
-Rezolvati problema [[https://​www.hackerrank.com/​contests/​test-practic-pa-2017-v2-meeseeks/​challenges/​test-2-pokemon-go-away-grea| Pokemon GO AWAY]] de la test PA 2017. 
  
-Cu ce problema ​seamana?+<spoiler Course schedule>​ 
 +Rezolvați ​problema ​[[https://​leetcode.com/​problems/​course-schedule/​description/​| course-schedule]] pe leetcode. 
 +(aplicație tipuri de muchii)
 </​spoiler>​ </​spoiler>​
  
-<spoiler insule>​ +===== Referințe ​=====
-Rezolvati problema [[https://​infoarena.ro/​problema/​insule +
-| insule]] pe infoarena. +
-</​spoiler>​ +
- +
-<spoiler tsunami>​ +
-Rezolvati problema [[https://​infoarena.ro/​problema/​tsunami +
-| tsunami]] pe infoarena. +
-</​spoiler>​ +
- +
- +
- +
-===== Referinte ​===== +
- +
-[1] [[http://​en.wikipedia.org/​wiki/​PageRank]] +
- +
-[2] [[http://​en.wikipedia.org/​wiki/​Social_network#​Social_network_analysis]] +
- +
-[3] [[http://​prefuse.org/​]] +
- +
-[4] [[http://​classes.engr.oregonstate.edu/​eecs/​spring2008/​cs419/​Lectures/​jun_graphcut.pdf]] +
- +
-[5] [[http://​en.wikipedia.org/​wiki/​Breadth-first_search]] +
- +
-[6] [[http://​en.wikipedia.org/​wiki/​Depth-first_search]]+
  
-[7[[http://en.wikipedia.org/​wiki/​Topological_sorting]]+[0Chapter **Elementary Graph Algorithms**,​ “Introduction to Algorithms”,​ Thomas HCormen, Charles ELeiserson, Ronald L. Rivest and Clifford Stein
  
-[8Introducere in Algoritmi, TCormen s.a., pag 403-419+[1[[https://​en.wikipedia.org/​wiki/​Tarjan%27s_strongly_connected_components_algorithm]]
  
-[9] [[http://ww3.algorithmdesign.net/handouts/DFS.pdf]]+[2] [[https://en.wikipedia.org/wiki/Biconnected_component]]
  
-[10[[http://​ww3.algorithmdesign.net/​handouts/​BFS.pdf]]+[3"​Depth-first search and linear graph algorithms",​ R.Tarjan ​
  
 +[4] [[https://​en.wikipedia.org/​wiki/​Kosaraju%27s_algorithm]]
pa/laboratoare/laborator-07.1523489760.txt.gz · Last modified: 2018/04/12 02:36 by darius.neatu
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