Differences

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

Link to this comparison view

pa:laboratoare:laborator-09 [2018/05/02 19:33]
radu_silviu.visan
pa:laboratoare:laborator-09 [2026/05/11 02:05] (current)
radu.nichita [Exerciții]
Line 1: Line 1:
-====== Laborator 09: Drumuri minime ======+====== Laborator 09: Drumuri minime ​în grafuri: surse / destinații multiple. (2/2) ====== 
 + 
 +{{:​pa:​new_pa:​partners:​adobe-logo.png?​250 |}} 
 +Adobe is a global technology leader with a mission to **change the world through personalized digital experiences**. For over four decades, Adobe has transformed how individuals,​ teams, businesses, and enterprises create, manage, and deliver content across every surface and channel. 
 + 
 +With **AI at the core**, tools like **Adobe Firefly** and AI-powered assistants make creativity faster, smarter, and more personalized—while keeping it safe and responsible. In **Adobe Experience Cloud**, AI powers real-time personalization,​ predictive insights, and automated customer journeys, helping brands deliver exceptional experiences at scale. At Adobe, **creativity meets productivity**,​ and AI is the catalyst for transformation.
  
 ===== Obiective laborator ===== ===== Obiective laborator =====
  
-  ​*Înțelegerea conceptelor de cost, relaxare a unei muchii, drum minim +În laboratorul anterior am introdus contextul pentru ​**Shortest-paths problem** și **Single-source shortest-paths problem**. ​În laboratorul 10 vom continua cu **All-pairs shortest-paths problem**.
-  ​*Prezentarea si asimilarea algoritmilor pentru calculul drumurilor minime+
  
-===== Importanţă – aplicaţii practice =====+  * Înțelegerea conceptelor de cost asociat unei muchii, relaxare a unei muchii. 
 +  * Prezentarea problemei drumului de cost minim (diverse variante). 
 +  * Prezentarea algoritmilor pentru calculul drumurilor minime.
  
-Algoritmii pentru determinarea drumurilor minime au multiple aplicații practice si reprezintă clasa de algoritmi pe grafuri cel mai des utilizata:+===== Shortest-paths problemall-pairs =====
  
-  *Rutare in cadrul unei rețele (telefonice,​ de calculatoare etc.) +Vă rugăm să parcugeți [[https://​ocw.cs.pub.ro/courses/​pa/​laboratoare/​shortest-paths-problem|Shortest-paths problem]] pentru a vă familiariza cu contextul, problema ​și notațiile folosite.
-  *Găsirea drumului minim dintre doua locații (Google Maps, GPS etc.+
-  *Stabilirea unei agende de zbor in vederea asigurării unor conexiuni optime +
-  *Asignarea unui peer server de fișiere in funcție de metricile definite pe fiecare linie de comunicație+
  
-===== Concepte ​=====+Concepte ​necesare:
  
-==== Costul ​unei muchii ​si al unui drum ====+  * **cost muchie** / **edge cost** 
 +  * **cost drum** / **path cost** 
 +  * **problema drumurilor minime: surse / destinații multiple** / **all-pairs shortest-paths problem** 
 +  * **relaxarea ​unei muchii** / **edge relaxation** 
 +  * **reconstruirea ​unui drum** / **RebuildPath**
  
-Fiind dat un graf orientat G (V, E), se considera funcția w: E -> W, numita funcție de cost, care asociază fiecărei muchii o valoare numerica. Domeniul funcției poate fi extins, pentru a include si perechile de noduri intre care nu exista muchie directa, caz in care valoarea este +∞ . Costul unui drum format din muchiile p12 p23 … p(n-1)n, având costurile w12, w23, …, w(n-1)n, este suma w w12 + w23 + … + w(n-1)n.+===== Algoritmi =====
  
-In exemplul alăturatcostul drumului de la nodul 1 la 5 este:+În acest laborator vom studia **all-pairs shortest-paths problem**. Pentru această problemă, vom prezenta 2 algoritmi:
  
-drumul 1w14 + w45 = 30 + 20 = 50+  * **Roy-Floyd**eficient pentru grafuri **dense** ($m >> n$ sau $|E| >> |V|$ - a.k.a. număr de muchii mult mai decât număr de noduri). 
 +  * **Johnson**:​ eficient pentru grafuri **rare** ($n >> m$ sau $|V| >> |E|$ - a.k.a. număr de noduri mult mai mare decât număr de muchii).
  
-drumul 2: w12 + w23 + w35 = 10 + 20 + 10 = 40+Vom prezenta fiecare algoritm, îl vom analiza, iar la final vom vedea când îl vom folosi pe fiecare.
  
-drumul 3: w13 + w35 = 50 + 10 = 60 +Puteți consulta capitolul **All-Pairs Shortest Paths** din **Introduction to Algorithms** [0] pentru mai multe detalii despre acești algoritmi.
-         +
-{{:​pa:​laboratoare:​8_1.png?300|}}+
  
-==== Drumul de cost minim ====+===== Roy-Floyd =====
  
-Costul minim al drumului dintre doua noduri este minimul dintre costurile drumurilor existente intre cele doua noduriIn exemplul de mai sus, drumul de cost minim de la nodul 1 la 5 este prin nodurile 2 si 3. +Algoritmul [[https://​en.wikipedia.org/​wiki/​Floyd%E2%80%93Warshall_algorithm|Roy-Floyd]] (**Roy-Floyd** / **Floyd–Warshall** algorithm) rezolvă **shortest-paths problem** în grafuri **G = (VE)** care sunt **dense**.
-Deșiin cele mai multe cazuri, costul este o funcție cu valori nenegative, exista situații in care un graf cu muchii de cost negativ are relevanta practicaO parte din algoritmi pot determina drumul corect de cost minim inclusiv pe astfel de grafuri. Totuși, nu are sens căutarea drumului minim in cazurile in care graful conține cicluri de cost negativ – un drum minim ar avea lungimea infinita, intrucat costul sau s-ar reduce la fiecare reparcurgere a ciclului:+
  
-In exemplul alăturat, ciclul 1 -> 2 -> 3 -> 1 are costul -20.        {{:​pa:​laboratoare:​8_2.png?​200|}}+==== Roy-Floyd Pseudocod ====
  
-drumul ​1: w12 + w23 + w35 10 + 20 + 10 40 +<code cpp> 
 +// apply Roy-Floyd'​s algorithm for all-pairs shortest-paths problem 
 +// 
 +// nodes     = list of all nodes from G 
 +// adj[node] = the adjacency list of node 
 +//             ​example:​ adj[node] = {..., neigh, ...} => edge (node, neigh) of cost w[node][neigh] 
 +// 
 +// 
 +// returns: d, p 
 +//          d = distance matrix 
 +//          p = parent matrix 
 +// 
 +Roy-Floyd(G=(nodes,​ adj)) { 
 +  // STEP 1: initialize results 
 +  // d[i][j] ​minimum distance from i to j 
 +  // p[i][j] ​parent of node j, on shortest path from i to j 
 +  for (i in nodes) { 
 +    for (j in nodes) { 
 +      d[i][j] = w[i][j]; ​                         // edge cost (or infinity if missing) 
 +      p[i][j] = (w[i][j] != infinity ? i : null); // parent (or null if missing) 
 +    } 
 +  }
  
-drumul ​2: (w12 + w23 + w31+ w12 + w23 + w35 = -20 10 + 20 10 20 +  // STEP 2: For each intermediar node k, 
 +  // try to update shortest path from i to j. 
 +  for (k in nodes
 +    for (i in nodes) { 
 +      for (j in nodes) { 
 +        // Is (i -> ... -> k) reunion with (k -> ... -> j) shorter than (i -> ... -> j)? 
 +        if (d[i][k] ​d[k][j] < d[i][j]) { 
 +          d[i][j] = d[i][k] ​d[k][j]; 
 +          p[i][j] ​p[k][j]; 
 +        } 
 +      } 
 +    } 
 +  }
  
-drumul 3: (w12 + w23 + w31) + (w12 + w23 + w31) + w12 + w23 + w35 = -20 + (-20) + 10 + 20 + 10 = 0 +  return d, p; 
 +}
  
-==== Relaxarea unei muchii ​====+// Usage example: 
 +d, p Roy-Floyd(G=(nodes, adj)); 
 +// 1. Use distances from d 
 +// 2. Rebuild path from node to source using parents (p) 
 +RebuildPath(source,​ destination,​ p); 
 +</​code>​ 
 +==== Exemple ​====
  
-Relaxarea unei muchii v1 v2 consta in a testa daca se poate reduce costul ei, trecând printr-un nod intermediar u. Fie w12 costul inițial al muchiei de la v1 la v2, w1u costul muchiei de la v1 la u, si wu2 costul muchiei de la u la v2. Daca w > w1u + wu2, muchia directa este înlocuita cu succesiunea de muchii v1 - u, u - v2.+=== Exemplu Roy-Floyd ===
  
-In exemplul alăturat, muchia de la 1 la 3, de cost w13 = 50, poate fi relaxata la costul 30, prin nodul intermediar u = 2, fiind înlocuita cu succesiunea w12, w23.+{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab10-graph-royfloyd-example.png?​512| Exemplu Roy-Floyd}}
  
-Toți algoritmii prezentați in continuare se bazează pe relaxare pentru a determina drumul minim. +Drumurile ​minime ​calculate ​de algoritmul Roy-Floyd sunt:
-{{:​pa:​laboratoare:​8_3.png?​200|}} +
-===== Drumuri ​minime de sursa unica =====+
  
-Algoritmii din aceasta secțiune determina drumul de cost minim de la un nod sursa, la restul nodurilor din graf, pe baza de relaxări repetate.+|-|1|2|3|4| \\ 
 +|1|0|-1|-2|0| \\ 
 +|2|4|0|2|4| \\ 
 +|3|5|1|0|2| \\ 
 +|4|3|-1|1|0| \\
  
-==== Algoritmul lui Dijkstra ==== 
  
-Dijkstra poate fi folosit doar in grafuri care au toate muchiile nenegative.+<spoiler Explicație pas cu pas> În exemplul atașat, avem un graf **orientat** cu următoare configurație:​
  
-Algoritmul este de tip Greedy: \\ +  * ''​%%n = 4%%'',​ ''​%%m = 5%%''​ 
-optimul local căutat este reprezentat ​de costul drumului dintre nodul sursa s si un nod vPentru fiecare nod se retine un cost estimat ​d[v], inițializat la început cu costul muchiei s -> v, sau cu +∞, daca nu exista muchie.+  * Funcția ​de cost ''​%%w%%''​ are valorile menționate pe muchii. 
 +  * Avem mai multe drumuri de cost diferite între diverse perechi de noduri din graf. 
 +  * Construim tabloul **d** al distanțelor minime: 
 +    * **d[u][v] = w[u][v]**dacă există muchia $(u, v)$. 
 +    * **d[u][v] = +∞, dacă **NU%%**%% există muchia $(u, v)$. 
 +    * **d[u][u] = 0**, convenție. 
 +    * Obținem matricea **d_0**:
  
-In exemplul următor, sursa s este nodul 1. Inițializarea va fi: \\ \\ +|-|1|2|3|4| ​\\ 
- {{:​pa:​laboratoare:​8_4.png?​500|}} \\ \\ +|1|0|+∞|-2|+∞| ​\\ 
-Aceste drumuri sunt îmbunătățite la fiecare pas, pe baza celorlalte costuri estimate.+|2|4|0|3|+∞| ​\\ 
 +|3|+∞|+∞|0|2| ​\\ 
 +|4|+∞|-1|+∞|0| \\
  
-Algoritmul selectează,​ in mod repetat, nodul u care are, la momentul respectiv, costul estimat minim (fata de nodul sursa). In continuare, se încearcă sa se relaxeze restul costurilor d[v]. Daca d[v] >= d[u] + wuv , d[v] ia valoarea d[u] + wuv. 
  
-Pentru a tine evidenta muchiilor care trebuie relaxatese folosesc doua structuri: S (mulțimea de vârfuri deja vizitate) si Q (o coada cu priorități,​ in care nodurile ​se afla ordonate după distanta fata de sursa) din care este mereu extras nodul aflat la distanta minima. In S se afla inițial ​doar sursa, iar in Q doar nodurile spre care exista muchie directa de la sursa, deci care au d[nod< +∞.+  * Rulăm algoritmul Roy-Floyd, vom scrie matricea pentru fiecare $ k = 12, 3, 4$. 
 +    * $d_1$ (matricea dupa primul pas din algoritm; ​se modifică doar **d[2][3]**)
  
-In exemplul de mai sus, vom inițializa S = {1} si Q = {243}.+|-|1|2|3|4| \\ 
 +|1|0|+∞|-2|+∞| \\ 
 +|2|4|0|**2**|+∞| \\ 
 +|3|+∞|+∞|0|2| \\ 
 +|4|+∞|-1|+∞|0| \\
  
-La primul pas este selectat nodul 2, care are d[2] = 10. \\  
-Singurul nod pentru care d[nod] poate fi relaxat este 3 : d[3] = 50 > d[2] + w23 = 10 + 20 = 30 \\ \\ 
- ​{{:​pa:​laboratoare:​8_5.png?​500|}} \\ \\ 
-După primul pas, S = {1, 2} si Q = {4, 3}. 
  
-La următorul pas este selectat nodul 4, care are d[4] = 30. \\  +  * $d_2$ (matricea dupa primul pas din algoritm; se modifică doar **d[4][3]** și **d[4][1]**)
-Pe baza lui, se poate modifica d[5d[5= +∞ > d[4+ w45 = 30 + 20 = 50 \\ \\ +
- ​{{:​pa:​laboratoare:​8_6.png?​500|}} \\ \\ +
-După al doilea pas, S = {1, 2, 4} si Q = {3, 5}.+
  
-La următorul pas este selectat nodul 3, care are d[3] = 30, si se modifica din nou d[5]: +|-|1|2|3|4| \\ 
-d[5] = 50 > d[3w35 = 30 10 = 40.+|1|0|+∞|-2|+∞| \\ 
 +|2|4|0|2|+∞| \\ 
 +|3|+∞|+∞|0|2| \\ 
 +|4|**3**|-1|**1**|0| v
  
-Algoritmul se încheie când coada Q devine vida, sau când S conține toate nodurile. Pentru a putea determina si muchiile ​din care este alcătuit drumul minim căutat, nu doar costul sau final, este necesar sa reținem un vector de părințP. Pentru nodurile care au muchie directa de la sursa, P[nodeste inițializat cu sursa, pentru restul cu null.+  * $d_3$ (matricea dupa primul pas din algoritm; se modifică doar **d[1][4]** ș**d[2][4]**)
  
-Pseudocodul pentru determinarea drumului minim de la o sursa către celelalte noduri utilizând algoritmul lui Dijkstra este:+|-|1|2|3|4| \\ 
 +|1|0|+∞|-2|**0**| \\ 
 +|2|4|0|2|**4**| \\ 
 +|3|+∞|+∞|0|2| \\ 
 +|4|3|-1|1|0| \\
  
-<code cpp> 
-Dijkstra(sursa,​ dest): 
-introdu sursa in Q 
-d[sursa] = 0 
-d[nod] = +∞ // pentru orice nod != sursa 
-P[nod] = null // pentru orice nod din V 
  
-// relaxari succesive +  * $d_4$ (matricea dupa primul pas din algoritm; se modifică doar **d[1][2]****d[3][1]** și **d[3][2]**)
-cat timp Q nu e vida +
-    u = extrage_min (Q) +
-    selectat(u) = true +
-    foreach nod in vecini[u] // (*+
-        /daca drumul de la sursa la nod prin u este mai mic decat cel curent */ +
-        daca not selectat(nod) si d[nod> d[u+ w[unod] +
-     // actualizeaza distanta si parinte +
-            ​d[nod= d[u+ w[u, nod] +
-            P[nod= u +
-            /actualizeaza pozitia nodului in coada prioritara ​*+
-            actualizeaza (Q,nod)+
  
-// gasirea drumului efectiv +|-|1|2|3|4| \\ 
-Initializeaza Drum = {} +|1|0|**-1**|-2|0| \\ 
-nod = P[dest] +|2|4|0|2|4| \\ 
-cat timp nod != null +|3|**5**|**1**|0|2| \\ 
-    ​insereaza nod la inceputul lui Drum +|4|3|-1|1|0| \\ 
-    nod = P[nod] + 
-</code>+ 
 +  * Drumurile minime sunt finale (cele menționate anterior - $d_4$). 
 + 
 +</spoiler\\ 
 + 
 + 
 +==== Complexitate ==== 
 + 
 +  * **complexitate temporală**:​ $T = O(n^3)\ sau\ O(|V|^3)$ 
 +  * **complexitate spațială** : $S = O(1)$
  
-Reprezentarea grafului ca matrice de adiacenta duce la o implementare ineficienta pentru orice graf care nu este complet, datorita parcurgerii vecinilor nodului u, din linia (*), care se va executa în |V| pași pentru fiecare extragere din Q, iar pe întreg algoritmul vor rezulta |V|^2 pași. Este preferata reprezentarea grafului cu liste de adiacenta, pentru care numărul total de operații cauzate de linia (*) va fi egal cu |E|. +<spoiler Detalii ​(analiză + optimizări)>
-Complexitatea algoritmului este O(|V|^2+|E|) în cazul în care coada cu priorități este implementata ca o căutare liniara. În acest caz funcția extrage_min se executa în timp O(|V|), iar actualizează(Q) in timp O(1).+
  
-O varianta mai eficienta este implementarea cozii ca heap binar. Funcția extrage_min se va executa în timp O(lg|V|); funcția actualizează(Q) se va executa tot în timp O(lg|V|), dar trebuie cunoscuta poziția cheii nod în heapadică heapul trebuie sa fie indexatComplexitatea obținută este O(|E|lg|V|) pentru un graf conex.+  * **complexitate temporală**: Se aplică recurența discutată anterior care pentru fiecare ​nod intermediar **k**încearcă să actualizeze drumul minim de la **i** la **j**Cele 3 foruri dau complexitatea temporară. 
 +  * **complexitate spațială** : Nu stocăm tablouri auxilare.
  
-Cea mai eficienta implementare se obține folosind un heap Fibonacci pentru coada cu priorități:​+</​spoiler>​ \\
  
-Aceasta este o structura de date complexa, dezvoltata în mod special pentru optimizarea algoritmului Dijkstra, caracterizata de un timp amortizat de O(lg|V|) pentru operația extrage_min si numai O(1) pentru actualizeaza(Q). Complexitatea obținută este O(|V|lg|V| + |E|), foarte bună pentru grafuri rare. 
  
-==== Algoritmul Bellman – Ford ====+===== Johnson =====
  
-Algoritmul ​Bellman Ford poate fi folosit si pentru grafuri ce conțin muchii de cost negativ, dar nu poate fi folosit pentru grafuri ce conțin cicluri de cost negativ ​(când căutarea unui drum minim nu are sens). \\  +Algoritmul ​lui [[https://​en.wikipedia.org/​wiki/​Johnson%27s_algorithm|Johnson]] ​(**Johnson’s algorithm**rezolvă **shortest-paths problem** în grafuri **G = (VE)** care sunt **rare**.
-Cu ajutorul sau putem afla daca un graf conține cicluri. +
-Algoritmul folosește același mecanism de relaxare ca si Dijkstra, dar, spre deosebire de acesta, nu optimizează o soluție folosind un criteriu de optim localci parcurge fiecare muchie de un număr de ori egal cu numărul de noduri si încearcă sa o relaxeze de fiecare data, pentru a îmbunătăți distanta până la nodul destinație al muchiei curente.+
  
-Motivul pentru ​care se face acest lucru este ca drumul minim dintre sursa si orice nod destinație poate sa treacă prin maximum |V| noduri ​(adică toate nodurile grafului)respectiv |V|-1 muchii; prin urmarerelaxarea tuturor muchiilor de |V|-1 ori este suficienta pentru a propaga până la toate nodurile informația despre distanta minima de la sursa.+Ideea de la care pornește ​acest algoritm ​este de a rula cel mai rapid algorithm pentru **shortest-paths single source**, adică algoritmul lui Dijkstra, pentru fiecare sursă (nod) din graf. Dacă toate costurile sunt pozitiveputem face direct acest lucru. Dacă însă există costuri negativenu putem aplica Dijkstra pe acest graf. Algoritmul lui Johnson face o preprocesare (în **ComputeH**) și calculează un graf echivalent, în care toate costurile sunt pozitive. Pe acest graf se poate aplica Dijkstra și să se afle toate distanțele. Ulterior se face translatarea inversă și se obțin **distanțele în graful inițial**.
  
-Daca, la sfârșitul acestor |E|*(|V|-1relaxărimai poate fi îmbunătățită o distanță, atunci graful are un ciclu de cost negativ si problema nu are soluție.+Observație:​ Dacă se știe că toate costurile din graf sunt pozitive ​(nenegative), algoritmul lui Johnson se poate înlocui cu rularea directă a algoritmului Dijkstra pentru toate nodurile din graf.
  
-Menținând notațiile anterioare, pseudocodul algoritmului este:+==== Johnson - Pseudocod ====
  
 <code cpp> <code cpp>
-BellmanFord(sursa):+// apply Johnson'​s algorithm for all-pairs shortest-paths problem 
 +// 
 +// nodes     = list of all nodes from G 
 +// adj[node] = the adjacency list of node 
 +//             ​example:​ adj[node] = {..., neigh, ...} => edge (node, neighof cost w[node][neigh] 
 +// 
 +// returnshas_cycle, d, p 
 +//          has_cycle = negative cycle detection flag (true if found) 
 +//          d = distance matrix (defined only if has_cycle == false) 
 +//          p = parent matrix (defined only if has_cycle == false) 
 +// 
 +Johnson(G=(nodes,​ adj)) { 
 +  // STEP 1: Compute adjustment distances h (using Bellmand-Ford). 
 +  has_cycle, h = ComputeH(G);​ 
 +  if (has_cycle) { 
 +    return true, null, null; 
 +  }
  
-d[sursa= 0 +  // STEP 2: Update all costs in G to obtain all costs nonnegative. 
-d[nod= +∞ // pentru orice nod != sursa +  foreach ((u, v) in edges) { 
-p[nod] = null // pentru orice nod din V+    if (w[u][v] != infinity) { 
 +      w[u][v] = w[u][v] + (h[u] - h[v]); 
 +    } 
 +  }
  
-// relaxari succesive +  ​// STEP 3: Now all costs are nonnegativeso we can apply Dijsktra. 
-// cum in initializare se face o relaxare (daca exista drum direct de la sursa la nod =>  +  // Start Dijkstra for each source ​u, saving just distances. 
-// d[nod] = w[sursanod]) mai sunt necesare |V-2| relaxari ​ +  foreach (u in nodes{ 
-for i = 1 to |V|-2  +    ​d_dijkstra, p_dijkstra = Dijkstra(u, G);
-    foreach (u, v) in E  // ​E = multimea muchiilor +
-        daca d[v] > d[u] + w(u,v) +
-            d[v] = d[u] + w(u,v) +
-            p[v] = u; +
-             +
-// daca se mai pot relaxa muchii +
-foreach (u, vin E +
-    ​daca d[v] > d[u] + w(u,v) +
-        fail (”exista cicluri negativ”) +
-</​code>​+
  
-Complexitatea algoritmului este O(|E|*|V|). +    // STEP 4: Compute distance ​(u, von initial graph
-  +    ​foreach (v in nodes) { 
-===== Drumuri minime intre oricare doua noduri =====+      ​d[u][v] ​d_dijkstra[v] + (h[v] - h[u]); 
 +      p[u][v] ​p_dijkstra[v];​ 
 +    } 
 +  }
  
-==== Floyd-Warshall ====+  return false, d, p;  // no negative cycles detected 
 +}
  
-Algoritmii din aceasta secțiune determina drumul de cost minim dintre oricare doua noduri dintr-un graf. Pentru ​rezolva aceasta problema s-ar putea aplica unul din algoritmii de mai susconsiderând ca sursa fiecare nod, pe rând, dar o astfel de abordare ar fi ineficienta.+ComputeH(G=(nodes,​ adj)){ 
 +  // STEP 0: Create ​new **temporary** graph 
 +  // * add a new node 
 +  source = new node; 
 +  new_nodes = nodes + { source }; 
 +  new_adj = adj; 
 +  // * add a new edge (sourcenode) with cost 0 for all existing nodes 
 +  for (node in nodes) { 
 +    new_adj[source].push_back(node);​ 
 +    w[source][node] = 0; 
 +  }
  
-Algoritmul Floyd-Warshall(intalnit si sub numele de Roy-Floydcompara toate drumurile posibile din graf dintre fiecare 2 nodurisi poate fi utilizat si in grafuri cu muchii de cost negativ.+  // STEP 1: Run Bellman-Ford on the new graph. Save just flag and distances. 
 +  has_cycle, h, _ = Bellmann-Ford(source,​ new_G=(new_nodes,​ new_adj))) 
 +  if (has_cycle) { 
 +    return truenull; // negative cycle detected 
 +  }
  
-Estimarea drumului optim poate fi reținut intr-o structura tridimensionala d[v1v2, k], cu semnificația – costul minim al drumului de la v1 la v2, folosind ca noduri intermediare doar noduri pana la nodul k. Daca nodurile sunt numerotate de la 1, atunci ​d[v1, v2, 0] reprezintă costul muchiei directe de la v1 la v2, considerând +∞ daca aceasta nu exista. Exemplu, pentru v1 = 1, respectiv 2: \\ \\  +  return false, d; 
- {{:​pa:​laboratoare:​8_7.png?​500|}} \\ \\  +}
-Pornind cu valori ale lui k de la 1 la |V|, ne interesează să găsim cea mai scurta cale de la fiecare v1 la fiecare v2 folosind doar noduri intermedire din mulțimea {1, ..., k}. De fiecare data, comparam costul deja estimat al drumului de la v1 la v2, deci d[v1, v2,   k-1] obținut la pasul anterior, cu costul drumurilor de la v1 la k si de la k la v2, adică d[v1, k, k-1] + d[k, v2, k-1], obținutae la pasul anterior. +
-Atunci, d[v1, v2, |V|] va conține costul drumului minim de la v1 la v2.+
  
-Pseudocodul acestui algoritm este: 
  
-<code cpp> +// Usage example
-FloydWarshall(G)+has_cycle, ​d, p = Johnson(sourceG=(nodesadj)); 
-n = |V| +if (has_cycle) { 
-int d[nnn] +  print "Has Cycle!"​ 
-foreach ​(ijin (1..n,1..n) +  STOP. 
-    ​d[i, j, 0] = w[i,​j] ​// costul muchiei, sau infinit +} else { 
-for k = 1 to +  // 1. Use distances from d 
-    foreach ​(i,j) in (1..n,1..n+  // (e.g. d[node] = distance from source to node) 
-        d[i, j, k] = min(d[ijk-1], d[i, k, k-1] + d[k, j, k-1])+  ​// 
 +  // 3. Rebuild path from node to source using parents ​(p
 +  ​RebuildPath(sourcedestinationp)
 +}
 </​code>​ </​code>​
 +==== Exemple ====
  
-Complexitatea temporala este O(|V|^3), iar cea spațială este tot O(|V|^3). +=== Exemplu Johnson ===
-O complexitate spațială cu un ordin mai mic se obține observând ca la un pas nu este nevoie decât de matricea de la pasul precedent d[i, j, k-1] si cea de la pasul curent d[i, j, k]. O observație și mai bună este că, de la un pas k-1 la k, estimările lungimilor nu pot decât sa scadă, deci putem sa lucram pe o singura matrice. Deci, spațiul de memorie necesar este de dimensiune |V|^2.+
  
-Rescris, pseudocodul algoritmului arata astfel:+În această secțiune exemplificăm grafic cum rulează algoritmul lui Johnson pe un graf dat.
  
-<code cpp> +<spoiler Explicație pas cu pas{{https://ocw.cs.pub.ro/courses/_media/​pa/​new_pa/​lab10-graph-johnson-example01.png?512| Exemplu Johnson ​1/3}}
-FloydWarshall(G): +
-n = |V| +
-int d[n, n] +
-foreach (i, j) in (1..n,1..n) +
-    d[i, j] = w[i,​j] ​// costul muchiei, sau infinit +
-for k = 1 to n +
-    foreach (i,j) in (1..n,1..n) +
-        d[i, j] = min(d[i, j], d[i, k] + d[k, j]) +
-</code>+
  
-Pentru a determina drumul efectiv, nu doar costul acestuia, avem doua variante:+În exemplul atașat, avem un graf **orientat** cu următoare configurație:
  
-1. Se retine o structura ​de părințisimilara cu cea de la Dijkstradarbineînțelesbidimensionala\\ +  * ''​%%n = 5%%'',​ ''​%%m = 8%%''​ 
-2. Se folosește divide et impera astfel:+  * Funcția de cost ''​%%w%%''​ are valorile menționate pe muchii. 
 +  * Avem mai multe drumuri ​de cost diferite între diverse perechi de noduri din graf. (Observăm că nu avem ciclu de cost negativdeci are sens să rulăm un algoritm ​de drumuri minime). 
 +  * ''​%%STEP 1%%'':​ Adăugăm un nod fictiv (exemplu nodul ''​%%6%%''​). Îl vom uni de fiecare nod din graful inițial (1234, 5) cu muchie de cost 0Obținem graful din figura următoare:
  
-se caută un pivot k astfel încât cost[i][j] = cost[i][k] + cost[j][k] \\ +{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab10-graph-johnson-example02.png?​512| Exemplu Johnson ​2/3}}
-se apelează funcția recursiv pentru ambele drumuri ​-> (i,k),(k,j) \\ +
-dacă pivotul nu poate fi găsit, afișăm i \\ +
-- după terminarea funcției recursie afișăm extremitatea dreapta a drumului \\+
  
-===== Cazuri speciale =====+  * Pe acest graf putem rula o dată algoritmul Bellman-Ford,​ considerând sursă noul nod adăugat. 
 +  * Obținem vectorul de distanțe $h[node] ​distanța\ de\ la\ nodul\ fictiv\ (6)\ la\ nodul\ node$
  
-1. Daca avem un graf **neorientat**,​ **fara cicluri** (un arbore), exista un singur +|node|1|2|3|4|5|6| \\ 
-drum intre oricare doua noduri, care poate fi aflat printr-o simpla parcurgere DFS. +|h[node]|-1|-7|-4|0|-2|0| \\
-Folosind diferite preprocesari ​[8],[9], putem calcula distanta intre oricare doua noduri +
-in timp constant, O(1).+
  
-2. Daca avem un graf **orientat**,​ **fara cicluri** (un DAG [10]), putem sa sa relaxam muchiile nodurilor, parcurgandu-le pe acestea in ordinea data de sortarea topologica. O(|V|+|E|) 
  
-3. Daca avem un graf unde toate muchiile au **cost egal**, putem afla distanta minima de la +  ​''​%%STEP 2%%'':​ Revenim la graful inițial (cel cu 5 noduri, 8 muchii) și îi alterăm costurile:​ 
-un nod sursa la orice alt nod printr-o parcurgere BFS. (de asemenea, tinand cont de faptul ca  +    ​$w[1][4] = w[1][4] + (h[1] - h[4]) = 2 + [ (-1) - (0) ] = 1$ 
-pot exista mai multe drumuri pana la un anumit nod). O(|V|+|E|)+    ​$w[2][1] = w[2][1] + (h[2] - h[1]) = 6 + [ (-7) - (-1) ] = 0$ 
 +    ​$w[2][3] = w[2][3] + (h[2] - h[3]) = 3 + [ (-7) - (-4) ] = 0$ 
 +    * $w[3][1] = w[3][1] + (h[3] h[1]) = 4 + [ (-4) - (-1) ] = 1$ 
 +    * $w[3][4] = w[3][4] + (h[3] - h[4]= 5 + [ (-4) - (0) ] = 1$ 
 +    * $w[4][2] = w[4][2] ​(h[4] - h[2]= -7 + [ (0) - (-7) ] = 0$ 
 +    * $w[4][5] = w[4][2] + (h[4] - h[2]) = -2 + [ (0) - (-2) ] = 0$ 
 +    * $w[5][4] = w[5][4] + (h[5] - h[4]) = -1 + [ (-2) - (-4) ] = 1$ 
 +  * Obținem graful din următoarea figură:
  
-4Pentru grafuri orientate, **rare** (relativ putine muchii), putem folosi algoritmul lui Johnson([11]) pentru  +{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab10-graph-johnson-example03.png?​512Exemplu Johnson - 2/3}}
-calcularea distantei minime de la un nod, la oricare alt nodO(|V|^2log|V| + |V||E|)+
  
-===== Concluzii ​=====+  * ''​%%STEP 3%%'':​ Deoarece toate costurile sunt pozitive, putem rula Dijkstra pe rând, pentru fiecare sursă ''​%%source ​1, 2, 3, 4, 5%%''​ din graf. 
 +  * ''​%%STEP 3%%'':​ $ source ​1 $ 
 +    * Vectorul de distanțe este ''​%%d_dijkstra%%''​ atașat mai jos. 
 +    * Distanțele față de nodul ''​%%1%%''​ pe graful inițial sunt: 
 +      * $d[1][1] ​0$ 
 +      * $d[1][2] ​d_{dijkstra}[2] + (h[2] - h[1]) 1 + [ (-7) - (-1) ] -5$ 
 +      * $d[1][3] ​d_{dijkstra}[3] + (h[3] - h[1]) 1 + [ (-4) - (-1) ] -2$ 
 +      * $d[1][4] ​d_{dijkstra}[4] + (h[4] - h[1]) = 1 + [ (0) - (-1) ] = 2$ 
 +      * $d[1][5] = d_{dijkstra}[5] + (h[5] - h[1]) = 1 + [ (-2) - (-1) ] = 0$
  
-    ***Dijkstra*** +|node|1|2|3|4|5| ​\\ 
-– calculează drumurile minime de la o sursa către celelalte noduri ​\\ +|d_dijkstra[node]|0|1|1|1|1| \\
-– nu poate fi folosit daca exista muchii de cost negativ \\ +
-– complexitate minima O(|V|lg|V|E|) utilizând heapuri Fibonacci;\\+
  
-    ***Bellman – Ford** 
-– calculează drumurile minime de la o sursă către celelalte noduri \\ 
-– detectează existența ciclurilor de cost negativ \\ 
-– complexitate O(|V| * |E|) \\ 
  
-    ***Floyd – Warshall** +|node|1|2|3|4|5| ​\\ 
-– calculează drumurile minime intre oricare doua noduri din graf \\ +|d[1][node]|0|-5|-2|2|0| \\
-– poate fi folosit in grafuri cu cicluri de cost negativ, dar nu le detectează \\ +
-– complexitate O(|V|^3) \\+
  
-===== Referinţe: ===== 
  
-[1] [[http://​en.wikipedia.org/​wiki/​Dijkstra'​s_algorithm]]+  * ''​%%STEP 3%%'':​ $ source = 2 $ 
 +    * Vectorul de distanțe este ''​%%d_dijkstra%%''​ atașat mai jos. 
 +    * Distanțele față de nodul ''​%%2%%''​ pe graful inițial sunt: 
 +      * $d[2][1] = d_{dijkstra}[1] + (h[1- h[2]) = 0 + [ (-1) - (-7) ] = 6$ 
 +      * $d[2][2] = 0$ 
 +      * $d[2][3] = d_{dijkstra}[3] + (h[3] - h[2]) = 0 + [ (-4) - (-7) ] = 3$ 
 +      * $d[2][4] = d_{dijkstra}[4] + (h[4] - h[2]) = 1 + [ (0) - (-7) ] = 8$ 
 +      * $d[2][5] = d_{dijkstra}[5] + (h[5] - h[2]) = 1 + [ (-2) - (-7) = 6$
  
-[2[[http://​en.wikipedia.org/​wiki/​Bellman-Ford_algorithm]]+|node|1|2|3|4|5| \\ 
 +|d_dijkstra[node]|0|0|0|1|1| \\
  
-[3] [[http://​www.algorithmist.com/​index.php/​Floyd-Warshall'​s_Algorithm]] 
  
-[4] [[http://​en.wikipedia.org/​wiki/​Binary_heap]]+|node|1|2|3|4|5| \\ 
 +|d[2][node]|6|0|3|8|6| \\
  
-[5] [[http://​en.wikipedia.org/​wiki/​Fibonacci_heap]] 
  
-[6T. Cormen, C. Leiserson, R. Rivest, C. Stein – Introducere în Algoritmi+  * ''​%%STEP 3%%'':​ $ source = 3 $ 
 +    * Vectorul de distanțe este ''​%%d_dijkstra%%''​ atașat mai jos. 
 +    * Distanțele față de nodul ''​%%3%%''​ pe graful inițial sunt: 
 +      * $d[3][1] = d_{dijkstra}[1] + (h[1] - h[3]) = 1 + [ (-1) - (-4) ] = 4$ 
 +      * $d[3][2] = d_{dijkstra}[2] + (h[2] - h[3]) = 1 + [ (-7) - (-4) ] = -2$ 
 +      * $d[3][3] = 0$ 
 +      * $d[3][4] = d_{dijkstra}[4] + (h[4] - h[3]) = 1 + [ (0) - (-4) ] = 5$ 
 +      * $d[3][5] = d_{dijkstra}[5] + (h[5] - h[3]) = 1 + [ (-2) - (-4) ] = 3$
  
-[7C. Giumale – Introducere în analiza algoritmilor+|node|1|2|3|4|5| \\ 
 +|d_dijkstra[node]|1|1|0|1|1| \\
  
-[8] http://​en.wikipedia.org/​wiki/​Range_Minimum_Query 
  
-[9http://​en.wikipedia.org/​wiki/​Lowest_common_ancestor+|node|1|2|3|4|5| \\ 
 +|d[3][node]|4|-2|0|5|3| \\
  
-[10] http://​en.wikipedia.org/​wiki/​Directed_acyclic_graph 
  
-[11] http://en.wikipedia.org/​wiki/​Johnson%27s_algorithm+  * ''​%%STEP 3%%''​$ source = 4 $ 
 +    * Vectorul de distanțe este ''​%%d_dijkstra%%''​ atașat mai jos. 
 +    * Distanțele față de nodul ''​%%4%%''​ pe graful inițial sunt: 
 +      * $d[4][1] = d_{dijkstra}[1] + (h[1] - h[4]) = 0 + [ (-1) - (0) ] = -1$ 
 +      * $d[4][2] = d_{dijkstra}[2] + (h[2] - h[4]) = 0 + [ (-7) - (0) ] = -7$ 
 +      * $d[4][3] = d_{dijkstra}[4] + (h[3] - h[4]) = 0 + [ (-4) - (0) ] = -4$ 
 +      * $d[4][4] = 0$ 
 +      * $d[4][5] = d_{dijkstra}[5] + (h[5] - h[4]) = 0 + [ (-2) - (0) ] = 2$
  
 +|node|1|2|3|4|5| \\
 +|d_dijkstra[node]|0|0|0|0|0| \\
  
-===== Resurse ===== 
  
-  * [[http://​cs.curs.pub.ro/​2015/​pluginfile.php/​32415/​mod_resource/​content/​1/​Lab%208%20Drumuri%20minime.pdf|Varianta PDF a laboratorului]] +|node|1|2|3|4|5| \\ 
-===== Exercitii ===== +|d[4][node]|-1|-7|-4|0|2| \\
-<​note>​ +
-In acest laborator vom folosi scheletul de laborator din arhiva {{pa:​new_pa:​skel-lab09.zip}}. +
-</​note>​+
  
-<note warning> 
-Inainte de a rezolva exercitiile,​ asigurati-va ca ati citit si inteles toate precizarile din sectiunea 
-[[https://​ocw.cs.pub.ro/​courses/​pa/​skel_graph | Precizari laboratoare 07-12]]. 
  
-Prin citirea acestor precizari va asigurati ca+  * ''​%%STEP 3%%''​$ source = 5 $ 
-   ​cunoasteti ​**conventiile** folosite +    Vectorul de distanțe este ''​%%d_dijkstra%%''​ atașat mai jos. 
-   * evitati **buguri*+    ​Distanțele față de nodul ''​%%4%%''​ pe graful inițial sunt: 
-   * evitati **depunctari*la lab/​teme/​test+      ​$d[5][1] = d_{dijkstra}[1] + (h[1] - h[5]) = 2 + [ (-1) - (-2) ] = 3$ 
 +      ​$d[5][2] = d_{dijkstra}[2] + (h[2] - h[5]) = 2 + [ (-7) - (-2) ] = -3$ 
 +      ​$d[5][3] = d_{dijkstra}[4] + (h[3] - h[5]) = 1 + [ (-4) - (-2) ] = -1$ 
 +      $d[5][4] = d_{dijkstra}[5] + (h[4] - h[5]) = 2 + [ (0) - (-2) ] = 4$ 
 +      $d[5][5] = 0$
  
-</​note>​+|node|1|2|3|4|5| \\ 
 +|d_dijkstra[node]|2|2|1|2|0| \\
  
-=== Dijkstra === 
-Se da un graf **orientat** cu **n** noduri si **m** arce. Graful are pe arce **costuri pozitive**. 
  
-Folositi **Dijkstra** pentru a gasi **costul minim** (**lungimea minima**) a unui drum de la o sursa data (**source**) la toate celelalte n - 1 noduri din graf.+|node|1|2|3|4|5| \\ 
 +|d[5][node]|3|-3|-1|4|0| \\
  
-Costul / lungimea unui drum este suma costurilor/​lungimilor arcelor care compun drumul. 
  
-<note warning>​ +  ​STOP! Am obținut toate distanțele ​$d[u][v]cerute!
-Restrictii si precizari:​ +
-  ​* $ n <= 50.000 ​$ +
-  * $ m <= 2.5 * 10^5 $ +
-  * $ 0 <= c <= 20.000$, unde c este costul/​lungimea unui arc +
-  * timp de executie +
-    * C++: 1s +
-    * Java: 2s +
-</​note>​+
  
-<note> +</spoiler\\
-Rezultatul se va returna sub forma unui vector **d** cu ** n  + 1** elemente.+
  
-Conventie: 
-  * ** d[node] ** = costul minim / lungimea minima a unui drum de la **source** la nodul **node** 
-  * ** d[source] = 0 ** 
-  * ** d[node] = -1 **, daca nu se poate ajunge de la **source** la **node** 
  
-d[0] nu este folosit, deci ca fi initializat cu 0! (am pastrat indexarea nodurilor de la 1) +==== Complexitate ====
-</​note>​+
  
 +  * **complexitate temporală**:​ $T = O(n * m * log (n))\ sau\ O(|V| * |E| * log (|V|))$
 +  * **complexitate spațială** : $S = O(n + m)\ sau \ O(|V| + |E|)$
  
-=== Bellman-Ford === +<spoiler Detalii (analiză + optimizări)>​
-Se da un graf **orientat conex** cu **n** noduri si **m** arce. Graful are pe arce **costuri pozitive sau negative**.+
  
-Folositi ​**Bellman-Ford** pentru a gasi **costul minim** (**lungimea minima**) a unui drum de la o sursa data (**source**) la toate celelalte ​n - 1 noduri din graf. In caz ca se va detecta un ciclu de cost negativ, se va semnala acest lucru.+  ​* **complexitate temporală**
 +    ​* **ComputeH**:​ 
 +      * Construire graf nou - $O(n + m))$. 
 +      ​Aplicare Bellman-Ford pe noul graf - $O(n m)$. 
 +    ​* **Update edges** - pasul se face în $O(m)$. 
 +    * Rularea Dijkstra pentru fiecare nod din graf - este complexitatea de la rulare Dijkstra pentru un singur nod sursă (a.k.a. $O(m log n)$), multiplicată cu numărul ​de noduri. 
 +    * În final ajungem ​la un total de $O(log(n) + n m + n + m) = O(n m + log(n))$. 
 +  * **complexitate spațială** : Se construiește un alt graf (**new_node** - n, **new_adj** ​m), se produc câțiva vectori temporari ​de lungime n (**h****d_dijkstra**,​ **p_dijkstra**). 
 +  * **optimizare**:​ Deoarece Dijsktra ​se poate optimiza (vezi laborator anterior), putem obține $O(n^2 * log n + n * m)$ complexitatea pentru ultima etapă. Complexitatea finală este $O(n ^ 2 log (m) + n * m)$.
  
-Costul ​lungimea unui drum este suma costurilor/​lungimilor arcelor care compun drumul.+</spoiler> \\
  
-<note warning> 
  
-Restrictii si precizari:​ +===== TLDR ===== 
-  * $ n <50.000 $ + 
-  * $ m <= 2.5 10^5 $ +  * Pentru cazul **shortest-path single source** am studiat în laboratorul anterior algoritmul lui Dijkstra ​algoritmul Bellman-Ford. 
-  ​-1.000 <= c <= +1.000$, unde c este costul/lungimea unui arc +  * Pentru cazul **shortest-path all-pairs**,​ discuția se facă după numărul ​de muchii din graf: 
-  * timp de executie +    * **graf dens**aplicăm Roy-Floyd și obținem $O(n ^ 3)$. 
-    * C++1s +    * **graf rar**aplicăm Johnson și obținem $O(n m * log (n))$. 
-    * Java2s + 
-  ​Pentru punctaj maxim, implementarea din laborator trebuie sa treaca toate testele, cu exceptia ultimelor 2, pe care va lua TLE. Pentru cei curiosi, exista si o implementare mai eficienta a algoritmului,​ oarecum similara cu cea de la Dijkstra ​(pentru mai multe detalii: [[https://​infoarena.ro/​problema/​bellmanford]]+===== Implementarea algoritmilor standard =====
-</​note>​+
  
 <​note>​ <​note>​
-Rezultatul se va returna sub forma unui vector **d** cu ** n + 1 ** elemente.+[[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​algorithms/​lab09|pa-lab/​algorithms/​lab09]] conține implementarea algoritmilor standard / tehnicilor / tiparelor de algoritmi pentru acest laborator. 
 +</​note>​
  
-Conventie: 
-  * ** d[node] ** = costul minim / lungimea minima a unui drum de la **source** la nodul **node** 
-  * ** d[source] = 0 ** 
-  * ** d[node] = -1 **, daca nu se poate ajunge de la **source** la **node** 
  
-d[0nu este folosit, deci ca fi initializat cu 0! (am pastrat indexarea nodurilor de la 1)+<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]]. 
 + 
 +Prin citirea acestor precizări vă asigurați că: 
 + 
 +  * știți **convențiile** folosite 
 +  * evitați **buguri** 
 +  * evitați **depunctări** ​la lab/​teme/​test 
  
-**ATENTIE!!!** Este posibil ca un astfel de graf sa aiba ciclu de cost negativ. In cazul detectarii unui ciclu de cost negativ, functia voastra va returna un vector gol! (**std::​vector<​int>​() / {}** sau ** new ArrayList<​Integer>​()**). 
 </​note>​ </​note>​
  
 +====== Pool probleme (pentru prezentări) ======
  
 +======= 1) Number of Possible Sets of Closing Branches =======
  
-=== RoyFloyd === +Enunț: O companie ​are ''​N''​ sucursale și mai multe drumuri bidirecționale,​ fiecare având o anumită distanță. O configurație a sucursalelor care rămân deschise este considerată validă dacă distanța minimă dintre oricare două sucursale deschise nu depășește o limită dată. Sarcina este să găsești numărul total de configurații valide (inclusiv configurația în care toate sucursalele sunt închise).
-Se da un graf **orientat** ​ cu **n** noduri. Graful ​are ** costuri pozitive** pe arce.+
  
-Se da ** matricea ponderilor **se cere **matricea drumurilor minime**.+Date de intrare: Un număr întreg ''​N''​ reprezentând numărul de sucursaleun număr întreg ''​maxDistance''​ reprezentând distanța maximă permisă și o matrice ''​roads'',​ unde fiecare element este un triplet ''​[u,​ v, weight]''​ ce reprezintă un drum bidirecțional și lungimea acestuia.
  
-<note warning>​ +Date de ieșireUn singur număr întreg reprezentând numărul total de configurații valide ​de sucursale.
-Restrictii si precizari: +
-  * $ n <= 100 $ +
-  * $ 0 <= c <= 1.000$, unde c este costul unui arc +
-  * daca **nu exista muchie** intre o pereche ​de noduri x si y, distanta ​de la nodul x la nodul y din **matricea ponderilor** va fi 0 +
-  * daca dupa aplicarea algoritmului **nu se gaseste drum** pentru o pereche de noduri x si y, se va considera **distanta** dintre ele egala cu 0 (se stocheaza in **matricea distantelor** valoarea 0) +
-  * drumul de la nodul i la nodul i are lungime 0 (prin conventie) +
-  * timp de executie +
-    * C++: 1s +
-    * Java: 2s +
-</​note>​+
  
-<​note>​ +Problema se poate testa la: 
-Rezultatul ​se va **stoca** in matricea **d** declarata in schelet! Algoritmul vostru trebuie doar sa o populeze corecttinand cont ca nodurile sunt indexate ​de la 1+[[https://​leetcode.com/​problems/​number-of-possible-sets-of-closing-branches/​description/​|LeetCode - Number of Possible Sets of Closing Branches]] 
-</​note>​+ 
 +======= 2) Minimum Cost to Convert String I ======= 
 + 
 +Enunț: Se dau două șiruri de caractere, ''​source''​ și ''​target'',​ de aceeași lungime, formate exclusiv din litere mici ale alfabetului englez, și trei vectori: ''​original'',​ ''​changed''​ și ''​cost''​. O literă din ''​original'' ​se poate transforma în litera corespunzătoare din ''​changed''​ plătind costul asociat din ''​cost''​. Se cere găsirea costului minim total pentru a transforma șirul ''​source''​ în șirul ''​target''​știind că operațiile ​de transformare pot fi aplicate în lanț de oricâte ori
 + 
 +Date de intrare: Șirurile de caractere ''​source''​ și ''​target'',​ împreună cu vectorii de transformare ''​original'',​ ''​changed''​ și ''​cost''​. 
 + 
 +Date de ieșire: Un singur număr întreg reprezentând costul minim pentru transformarea întregului șir, sau -1 dacă transformarea este imposibilă.
  
-=== BONUS === +Problema se poate testa la
-Pentru exercitiul cu Dijkstra, **reconstituiti** drumul de lungime minima **source** ​la celelalte noduri din graf.+[[https://​leetcode.com/​problems/​minimum-cost-to-convert-string-i/​|LeetCode - Minimum Cost to Convert String I]]
  
-Folositi fisierele din {{pa:​new_pa:​skel-lab09.zip}} din folderul **bonus** ca sa va verificati. ​+======= 3) Roy-Floyd Invers (rfinv) =======
  
-Pentru fisierul mare, folositi comanda **diff ** cu parametrul ** -w ** pentru a verifica usor ca outputul coincide.+Enunț: Se dă o matrice de dimensiune ''​N × N''​ care reprezintă potențialele distanțe minime dintre oricare două noduri dintr-un graf orientat (adică rezultatul aplicării algoritmului Roy-Floyd). Se cere să se verifice dacă această matrice este validă și, în caz afirmativ, să se determine numărul minim de muchii pe care ar trebui să le aibă graful inițial ​pentru a genera exact aceste distanțe.
  
-=== Extra === +Date de intrareNumărul de teste ''​T''​Pentru fiecare test, se dă numărul de noduri ''​N'',​ urmat de o matrice de dimensiune ''​N × N''​ ce reprezintă distanțele.
-<spoiler rfinv> +
-Rezolvati problema [[https://infoarena.ro/​problema/​rfinv| rfinv]] pe infoarena. +
-</​spoiler>​+
  
 +Date de ieșire: Pentru fiecare test, se va afișa pe o linie separată "​NU"​ dacă nu se poate construi un astfel de graf. Dacă este posibil, se va afișa "​DA",​ urmat de un spațiu și de numărul minim de muchii ale grafului inițial.
  
-<spoiler coach> +Problema se poate testa la: 
-Rezolvati problema ​[[https://​infoarena.ro/​problema/​coachcoach]] pe infoarena. +[[https://​infoarena.ro/​problema/​rfinv|Infoarena - rfinv]]
-</​spoiler>​+
  
  
 +==== Extra ====
  
-<spoiler rf> +  * [[https://​infoarena.ro/​problema/​rfinv|infoarena/​rfinv]] 
-Rezolvati ​problema [[https://​infoarena.ro/​problema/​rf| rf]] pe infoarena. +  * [[https://​infoarena.ro/​problema/​rf|infoarena/rf]] 
-</spoiler>+  * [[https://infoarena.ro/​problema/​coach|infoarena/​coach]] 
 +  * [[https://​codeforces.com/​contest/​295/​problem/​B|codeforces/​greg-and-graph]] 
 +  * [[https://​codeforces.com/​contest/​25/​problem/​C|codeforces/​roads-in-berland]] 
 +  * [[https://​codeforces.com/​problemset/​problem/​21/​D|codeforces/​traveling-graph]] 
 +  * [[https://​codeforces.com/​gym/​101498/​problem/​L|codeforces/​the-shortest-path]]
  
 +===== Referințe =====
  
-<spoiler TODO> +[0] Chapters **Single-Source Shortest Paths** ​**All-Pairs Shortest Paths**, “Introduction to Algorithms”,​ Thomas HCormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein.
-Rezolvati problema ​[[https://infoarena.ro/​problema/​TODO| TODO]] pe infoarena. +
-</​spoiler>​+
  
pa/laboratoare/laborator-09.1525278780.txt.gz · Last modified: 2018/05/02 19:33 by radu_silviu.visan
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