Differences

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

Link to this comparison view

pa:laboratoare:laborator-09 [2022/04/30 00:59]
darius.neatu
pa:laboratoare:laborator-09 [2025/05/21 17:19] (current)
matei.mantu fix typo
Line 1: Line 1:
-Delete old lab.a+====== Laborator 09: Drumuri minime în grafuri: surse / destinații multiple. (2/2) ====== 
 + 
 + 
 +{{:​pa:​new_pa:​partners:​adobe-logo.png?​155 |}} 
 +\\ \\ \\ Changing the world through digital experiences is what Adobe’s all about. We give everyone - from emerging artists to global brands - everything they need to design and deliver exceptional digital experiences! We’re passionate about empowering people to create beautiful and powerful images, videos, and apps, and transform how companies interact with customers across every screen. 
 + 
 +===== Obiective laborator ===== 
 + 
 +Î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**. 
 + 
 +  * Î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. 
 + 
 +===== Shortest-paths problem: all-pairs ===== 
 + 
 +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. 
 + 
 +Concepte necesare: 
 + 
 +  * **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** 
 + 
 +===== Algoritmi ===== 
 + 
 +În acest laborator vom studia **all-pairs shortest-paths problem**. Pentru această problemă, vom prezenta 2 algoritmi:​ 
 + 
 +  * **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). 
 + 
 +Vom prezenta fiecare algoritm, îl vom analiza, iar la final vom vedea când îl vom folosi pe fiecare. 
 + 
 +Puteți consulta capitolul **All-Pairs Shortest Paths** din **Introduction to Algorithms** [0] pentru mai multe detalii despre acești algoritmi. 
 + 
 +===== Roy-Floyd ===== 
 + 
 +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 = (V, E)** care sunt **dense**. 
 + 
 +==== Roy-Floyd - Pseudocod ==== 
 + 
 +<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) 
 +    } 
 +  } 
 + 
 +  // 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]; 
 +        } 
 +      } 
 +    } 
 +  } 
 + 
 +  return d, p; 
 +
 + 
 +// 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 ==== 
 + 
 +=== Exemplu Roy-Floyd === 
 + 
 +{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab10-graph-royfloyd-example.png?​512| Exemplu Roy-Floyd}} 
 + 
 +Drumurile minime calculate de algoritmul Roy-Floyd sunt: 
 + 
 +|-|1|2|3|4| \\ 
 +|1|0|-1|-2|0| \\ 
 +|2|4|0|2|4| \\ 
 +|3|5|1|0|2| \\ 
 +|4|3|-1|1|0| \\ 
 + 
 + 
 +<spoiler Explicație pas cu pas> În exemplul atașat, avem un graf **orientat** cu următoare configurație:​ 
 + 
 +  * ''​%%n = 4%%'',​ ''​%%m = 5%%''​ 
 +  * 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**: 
 + 
 +|-|1|2|3|4| \\ 
 +|1|0|+∞|-2|+∞| \\ 
 +|2|4|0|3|+∞| \\ 
 +|3|+∞|+∞|0|2| \\ 
 +|4|+∞|-1|+∞|0| \\ 
 + 
 + 
 +  * Rulăm algoritmul Roy-Floyd, vom scrie matricea pentru fiecare $ k = 1, 2, 3, 4$. 
 +    * $d_1$ (matricea dupa primul pas din algoritm; se modifică doar **d[2][3]**) 
 + 
 +|-|1|2|3|4| \\ 
 +|1|0|+∞|-2|+∞| \\ 
 +|2|4|0|**2**|+∞| \\ 
 +|3|+∞|+∞|0|2| \\ 
 +|4|+∞|-1|+∞|0| \\ 
 + 
 + 
 +  * $d_2$ (matricea dupa primul pas din algoritm; se modifică doar **d[4][3]** și **d[4][1]**) 
 + 
 +|-|1|2|3|4| \\ 
 +|1|0|+∞|-2|+∞| \\ 
 +|2|4|0|2|+∞| \\ 
 +|3|+∞|+∞|0|2| \\ 
 +|4|**3**|-1|**1**|0| v 
 + 
 +  * $d_3$ (matricea dupa primul pas din algoritm; se modifică doar **d[1][4]** și **d[2][4]**) 
 + 
 +|-|1|2|3|4| \\ 
 +|1|0|+∞|-2|**0**| \\ 
 +|2|4|0|2|**4**| \\ 
 +|3|+∞|+∞|0|2| \\ 
 +|4|3|-1|1|0| \\ 
 + 
 + 
 +  * $d_4$ (matricea dupa primul pas din algoritm; se modifică doar **d[1][2]**,​ **d[3][1]** și **d[3][2]**) 
 + 
 +|-|1|2|3|4| \\ 
 +|1|0|**-1**|-2|0| \\ 
 +|2|4|0|2|4| \\ 
 +|3|**5**|**1**|0|2| \\ 
 +|4|3|-1|1|0| \\ 
 + 
 + 
 +  * 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)$ 
 + 
 +<spoiler Detalii (analiză + optimizări)>​ 
 + 
 +  * **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. 
 + 
 +</​spoiler>​ \\ 
 + 
 + 
 +===== Johnson ===== 
 + 
 +Algoritmul lui [[https://​en.wikipedia.org/​wiki/​Johnson%27s_algorithm|Johnson]] (**Johnson’s algorithm**) rezolvă **shortest-paths problem** în grafuri **G = (V, E)** care sunt **rare**. 
 + 
 +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 pozitive, putem face direct acest lucru. Dacă însă există costuri negative, nu 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**. 
 + 
 +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. 
 + 
 +==== Johnson - Pseudocod ==== 
 + 
 +<code cpp> 
 +// 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, neigh) of cost w[node][neigh] 
 +// 
 +// returns: has_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; 
 +  } 
 + 
 +  // STEP 2: Update all costs in G to obtain all costs nonnegative. 
 +  foreach ((u, v) in edges) { 
 +    if (w[u][v] != infinity) { 
 +      w[u][v] = w[u][v] + (h[u] - h[v]); 
 +    } 
 +  } 
 + 
 +  // STEP 3: Now all costs are nonnegative,​ so we can apply Dijsktra. 
 +  // Start Dijkstra for each source u, saving just distances. 
 +  foreach (u in nodes) { 
 +    d_dijkstra, p_dijkstra = Dijkstra(u, G); 
 + 
 +    // STEP 4: Compute distance (u, v) on initial graph. 
 +    foreach (v in nodes) { 
 +      d[u][v] = d_dijkstra[v] + (h[v] - h[u]); 
 +      p[u][v] = p_dijkstra[v];​ 
 +    } 
 +  } 
 + 
 +  return false, d, p;  // no negative cycles detected 
 +
 + 
 +ComputeH(G=(nodes,​ adj)){ 
 +  // STEP 0: Create a new **temporary** graph 
 +  // * add a new node 
 +  source = new node; 
 +  new_nodes = nodes + { source }; 
 +  new_adj = adj; 
 +  // * add a new edge (source, node) with cost 0 for all existing nodes 
 +  for (node in nodes) { 
 +    new_adj[source].push_back(node);​ 
 +    w[source][node] = 0; 
 +  } 
 + 
 +  // 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 true, null; // negative cycle detected 
 +  } 
 + 
 +  return false, d; 
 +
 + 
 + 
 +// Usage example: 
 +has_cycle, d, p = Johnson(source,​ G=(nodes, adj)); 
 +if (has_cycle) { 
 +  print "Has Cycle!"​ 
 +  STOP. 
 +} else { 
 +  // 1. Use distances from d 
 +  // (e.g. d[node] = distance from source to node) 
 +  // 
 +  // 3. Rebuild path from node to source using parents (p) 
 +  RebuildPath(source,​ destination,​ p); 
 +
 +</​code>​ 
 +==== Exemple ==== 
 + 
 +=== Exemplu Johnson === 
 + 
 +În această secțiune exemplificăm grafic cum rulează algoritmul lui Johnson pe un graf dat. 
 + 
 +<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}} 
 + 
 +În exemplul atașat, avem un graf **orientat** cu următoare configurație:​ 
 + 
 +  * ''​%%n = 5%%'',​ ''​%%m = 8%%''​ 
 +  * 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 negativ, deci 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 (1, 2, 3, 4, 5) cu muchie de cost 0. Obținem graful din figura următoare:​ 
 + 
 +{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab10-graph-johnson-example02.png?​512| Exemplu Johnson - 2/3}} 
 + 
 +  * 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$ 
 + 
 +|node|1|2|3|4|5|6| \\ 
 +|h[node]|-1|-7|-4|0|-2|0| \\ 
 + 
 + 
 +  * ''​%%STEP 2%%'':​ Revenim la graful inițial (cel cu 5 noduri, 8 muchii) și îi alterăm costurile:​ 
 +    * $w[1][4] = w[1][4] + (h[1] - h[4]) = 2 + [ (-1) - (0) ] = 1$ 
 +    * $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ă: 
 + 
 +{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab10-graph-johnson-example03.png?​512| Exemplu Johnson - 2/3}} 
 + 
 +  * ''​%%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$ 
 + 
 +|node|1|2|3|4|5| \\ 
 +|d_dijkstra[node]|0|1|1|1|1| \\ 
 + 
 + 
 +|node|1|2|3|4|5| \\ 
 +|d[1][node]|0|-5|-2|2|0| \\ 
 + 
 + 
 +  * ''​%%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$ 
 + 
 +|node|1|2|3|4|5| \\ 
 +|d_dijkstra[node]|0|0|0|1|1| \\ 
 + 
 + 
 +|node|1|2|3|4|5| \\ 
 +|d[2][node]|6|0|3|8|6| \\ 
 + 
 + 
 +  * ''​%%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$ 
 + 
 +|node|1|2|3|4|5| \\ 
 +|d_dijkstra[node]|1|1|0|1|1| \\ 
 + 
 + 
 +|node|1|2|3|4|5| \\ 
 +|d[3][node]|4|-2|0|5|3| \\ 
 + 
 + 
 +  * ''​%%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| \\ 
 + 
 + 
 +|node|1|2|3|4|5| \\ 
 +|d[4][node]|-1|-7|-4|0|2| \\ 
 + 
 + 
 +  * ''​%%STEP 3%%'':​ $ source = 5 $ 
 +    * Vectorul de distanțe este ''​%%d_dijkstra%%''​ atașat mai jos. 
 +    * Distanțele față de nodul ''​%%4%%''​ pe graful inițial sunt: 
 +      * $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$ 
 + 
 +|node|1|2|3|4|5| \\ 
 +|d_dijkstra[node]|2|2|1|2|0| \\ 
 + 
 + 
 +|node|1|2|3|4|5| \\ 
 +|d[5][node]|3|-3|-1|4|0| \\ 
 + 
 + 
 +  * STOP! Am obținut toate distanțele $d[u][v]$ cerute! 
 + 
 +</​spoiler>​ \\ 
 + 
 + 
 +==== Complexitate ==== 
 + 
 +  * **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|)$ 
 + 
 +<spoiler Detalii (analiză + optimizări)>​ 
 + 
 +  * **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(n * m * 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)$. 
 + 
 +</​spoiler>​ \\ 
 + 
 + 
 +===== TLDR ===== 
 + 
 +  * Pentru cazul **shortest-path single source** am studiat în laboratorul anterior algoritmul lui Dijkstra / algoritmul Bellman-Ford. 
 +  * Pentru cazul **shortest-path all-pairs**,​ discuția se facă după numărul de muchii din graf: 
 +    * **graf dens**: aplicăm Roy-Floyd și obținem $O(n ^ 3)$. 
 +    * **graf rar**: aplicăm Johnson și obținem $O(n * m * log (n))$. 
 + 
 +===== Exerciții ===== 
 + 
 + 
 +<​note>​ 
 + 
 +Scheletul de laborator se găsește pe pagina [[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​skel/​lab10|pa-lab::​skel/​lab10]]. 
 + 
 +</​note>​ 
 +<note warning>​ 
 + 
 +Înainte de 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 
 + 
 + 
 +</​note>​ 
 + 
 +==== Task-1: Roy-Floyd ==== 
 + 
 +Se dă un graf **orientat** cu **n** noduri. Graful are **costuri strict pozitive**. 
 + 
 +Se dă matricea ponderilor - **w**, se cere matricea drumurilor minime - **d**, aplicând algoritmul **Roy-Floyd**. 
 + 
 + 
 +<note warning>​ 
 + 
 +Restricții și precizări:​ 
 + 
 +  * $ n <= 100 $ 
 +  * $ 0 <= c <= 1.000$, unde c este costul unui arc. 
 +    * Dacă **nu există arc** între o pereche de noduri x și y, distanța de la nodul x la nodul y din **matricea ponderilor** va fi 0. 
 +    * Dacă după aplicarea algoritmului **nu se găsește drum** pentru o pereche de noduri x și y, se va considera **distanța** dintre ele egală cu 0 (se stochează în **matricea distantelor** valoarea 0). 
 +    * Drumul de la nodul i la nodul i are lungime 0 (prin convenție). 
 +  * timp de execuție 
 +    * C++: 1s 
 +    * Java: 8s 
 + 
 + 
 +</​note>​ 
 + 
 +==== Task-2: Johnson ==== 
 + 
 +Se dă un graf **orientat** cu **n** noduri. Graful are **costuri oarecare** (pot fi și negative). 
 + 
 +Se dă lista de adiacență cu costurile aferente, se cere matricea drumurilor minime - **d**, aplicând algoritmul **Johnson**. 
 + 
 + 
 +<note warning>​ 
 + 
 +Restricții și precizări:​ 
 + 
 +  * $ n <= 1000 $ 
 +  * $ m <= 25000 $ 
 +  * $ -1000 <= c <= 1.000$, unde c este costul unui arc. 
 +    * Dacă **nu există arc** între o pereche de noduri x și y, distanța de la nodul x la nodul y din **matricea ponderilor** va fi 0. 
 +    * Dacă după aplicarea algoritmului **nu se găsește drum** pentru o pereche de noduri x și y, se va considera **distanța** dintre ele egală cu 0 (se stochează în **matricea distantelor** valoarea 0). 
 +    * Drumul de la nodul i la nodul i are lungime 0 (prin convenție). 
 +    * Dacă graful conține un ciclu de cost negativ, se va afișa mesajul: Ciclu negativ! 
 +  * timp de execuție 
 +    * C++: 1s 
 +    * Java: 8s 
 + 
 + 
 +</​note>​ 
 + 
 +=== Task-3: Orașul care poate accesa cele mai puține noduri (dându-se o distanță limită) === 
 +Rezolvați problema [[ https://​leetcode.com/​problems/​find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance/​description/​ | Find the City With the Smallest Number of Neighbors at a Threshold Distance ]] pe LeetCode. 
 + 
 + 
 +==== BONUS ==== 
 + 
 +La acest laborator, asistentul va alege 1-2 probleme din secțiunea extra. 
 + 
 +==== Extra ==== 
 + 
 +  * [[https://​infoarena.ro/​problema/​rfinv|infoarena/​rfinv]] 
 +  * [[https://​infoarena.ro/​problema/​rf|infoarena/​rf]] 
 +  * [[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 ===== 
 + 
 +[0] Chapters **Single-Source Shortest Paths** / **All-Pairs Shortest Paths**, “Introduction to Algorithms”,​ Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein. 
pa/laboratoare/laborator-09.1651269560.txt.gz · Last modified: 2022/04/30 00:59 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