Differences

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

Link to this comparison view

pa:laboratoare:laborator-09 [2013/04/19 19:23]
constantin.tudorica1305 [Exemplu de rulare]
pa:laboratoare:laborator-09 [2024/05/09 18:24] (current)
radu.nichita
Line 1: Line 1:
-====== Laborator 9 - Arbori Minimi de Acoperire ​======+====== 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 ===== ===== Obiective laborator =====
-  *Însuşirea conceptului de arbore minim de acoperire; 
-  *Înţelegerea modului de funcţionare a algoritmilor de determinare a unui arbore minim de acoperire prezentaţi;​ 
-  *Aplicarea algoritmilor în rezolvarea problemelor;​ 
  
-===== Importanţă – aplicaţii practice =====+Î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**.
  
-Găsirea unui arbore minim de acoperire pentru un graf are aplicaţii în domenii cât se poate de variate: +  ​Înțelegerea conceptelor ​de cost asociat unei muchiirelaxare ​a unei muchii
-  ​*Reţele (de calculatoare,​ telefonie, cablu TV, electricitate,​ drumuri): se doreşte interconectarea mai multor puncte, cu un cost redus şi atunci este utilă cunoaşterea arborelui care conectează toate punctelecu cel mai mic cost posibil. STP(Spanning Tree Protocol) este un protocol de rutare care previne apariţia buclelor într-un LAN, şi se bazează pe crearea unui arbore de acoperire. Singurele legături active sunt cele care apar în acest arbore, iar astfel se evită buclele. +  * Prezentarea problemei drumului ​de cost minim (diverse variante)
-  *Segmentarea imaginilor: împărţirea unei imagini în regiuni de pixeli cu proprietăţi asemănătoare. E utilă mai apoi în analiza medicală ​a unei zone afectate de o tumoare de exemplu+  * Prezentarea algoritmilor ​pentru ​calculul drumurilor minime.
-  *Algoritmi ​de aproximare pt probleme NP-dure: problema comis-voiajorului,​ arbori Steiner+
-  *Clustering: ​pentru ​detectarea de clustere cu forme neregulate [8], [9].+
  
-===== Descrierea problemei şi a rezolvărilor ​=====+===== Shortest-paths problem: all-pairs ​=====
  
-Dându-se un graf conex neorientat G =(V, E), se numeşte arbore de acoperire al lui G un subgraf G’=(V, E’)  care conţine toate vârfurile grafului G şi o submulţime minimă de muchii E’⊆ E cu proprietatea că uneşte toate vârfurile şnu conţine cicluriCum G’ este conex şi aciclic, el este arborePentru un graf oarecareexistă mai mulţarbori de acoperire.+Vă rugăm să parcugeț[[https://​ocw.cs.pub.ro/​courses/​pa/​laboratoare/​shortest-paths-problem|Shortest-paths problem]] pentru a vă familiariza cu contextulproblema șnotațiile folosite.
  
-Dacă asociem o matrice de costuri, w, pentru ​muchiile din G, fiecare arbore de acoperire va avea asociat un cost egal cu suma costurilor muchiilor conţinute. Un arbore care are costul asociat mai mic sau egal cu costul oricărui alt arbore ​de acoperire se numeşte arbore minim de acoperire (minimum spanning treeal grafului GUn graf poate avea mai mulţi arbori minimi de acoperireDacă toate costurile muchiilor sunt diferite, există un singur AMA.  +Concepte necesare: 
-Primul ​algoritm ​pentru determinarea unui arbore minim de acoperire a fost scris în 1926 de Otakar Boruvka. În prezentcei mai folosiţi algoritmi sunt Prim şi KruskalToţtrei sunt algoritmi ​greedy, şi rulează în timp polinomial. La fiecare paspentru a construi arborele se alege cea mai bună variantă posibilă la momentul respectivGeneric, algoritmul de determinare a unui AMA se poate scrie astfel:+ 
 +  * **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ăde muchii mult mai decât număr ​de noduri). 
 +  * **Johnson**:​ eficient pentru grafuri **rare** ($n >> m$ sau $|V| >> |E|$ - a.k.anumă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ț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 = (VE)** care sunt **dense**. 
 + 
 +==== Roy-Floyd - Pseudocod ====
  
 <code cpp> <code cpp>
-ArboreMinimDeAcoperire(G(VE), c+// apply Roy-Floyd'​s algorithm for all-pairs shortest-paths problem 
- MuchiiAMA ​; +// 
- while ​(MuchiiAMA nu reprezintă muchiile unui arbore minim de acoperire+// nodes     = list of all nodes from G 
- găseşte o muchie ​(uvcare este sigură pentru MuchiiAMA+// adj[node] = the adjacency list of node 
- MuchiiAMA ​MuchiiAMA ∪ {(uv)}+//             ​example:​ adj[node] = {..., neigh, ...} => edge (node, neigh) of cost w[node][neigh] 
- return MuchiiAMA;+// 
 +// 
 +// returns: d, p 
 +//          d = distance matrix 
 +//          p = parent matrix 
 +// 
 +Roy-Floyd(G=(nodesadj)) { 
 +  // STEP 1: initialize results 
 +  // d[i][j] = minimum distance from i to j 
 +  // p[i][j] = parent of node jon 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=(nodesadj)); 
 +// 1. Use distances from d 
 +// 2. Rebuild path from node to source using parents (p) 
 +RebuildPath(source,​ destination,​ p);
 </​code>​ </​code>​
 +==== Exemple ====
  
-O muchie sigură este o muchie care se poate adăuga unei submulţimi de muchii ale unui arbore minim de acoperire, astfel încât noua mulţime obţinută să aparţină tot unui arbore minim de acoperire. Iniţial, MuchiiAMA este o mulţime vidă. La fiecare pas, se adaugă câte o muchie sigură, deci MuchiiAMA rămâne o submulţime a unui AMA. În consecinţă,​ la sfarşitul rulării algoritmului (când muchiile din mulţime unesc toate nodurile din graf), MuchiiAMA va conţine de fapt arborele minim de acoperire dorit. +=== Exemplu Roy-Floyd ​===
-  +
-==== Algoritmul Kruskal ====+
  
-Algoritmul a fost dezvoltat în 1956 de Joseph KruskalDeterminarea arborelui minim de acoperire se face prin reuniuni de subarbori minimi de acoperireIniţial, se consideră că fiecare nod din graf este un arboreApoi, la fiecare pas se selectează muchia de cost minim care uneşte doi subarbori disjuncţi, şi se realizează unirea celor doi subarbori. Muchia respectivă se adaugă la mulţimea MuchiiAMA, care la sfârşit va conţine chiar muchiile din arborele minim de acoperire+{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab10-graph-royfloyd-example.png?512| Exemplu Roy-Floyd}}
  
-===== Pseudocod ​=====+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> <code cpp>
-Kruskal(G(VE)w) +// apply Johnson'​s algorithm for all-pairs shortest-paths problem 
-MuchiiAMA <+// 
-for each v in V do +// nodes     = list of all nodes from G 
- MakeSet(v); //fiecare nod e un arbore diferit +// adj[node] = the adjacency list of node 
-sort(E); //sortează muchiile în ordine crescătoare a costului +//             ​example:​ adj[node] = {..., neigh, ...} => edge (nodeneighof cost w[node][neigh] 
-for each (u,v) in E do +// 
-if (FindSet(u) !FindSet(v)) then //capetele muchiei fac parte //din subarbori disjuncţi +// returns: has_cycle, d, p 
- MuchiiAMA ​MuchiiAMA ∪ {(uv)}; //adaugă muchia la arbore +//          has_cycle = negative cycle detection flag (true if found
-Union(uv)   //uneşte subarborii corespunzători lui u şi v +//          d = distance matrix (defined only if has_cycle == false) 
-return ​MuchiiAMA;+//          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 = ComputerH(G)
 +  if (has_cycle) { 
 +    return true, null, null; 
 +  } 
 + 
 +  // STEP 2: Update all costs in G to obtain all costs nonnegative. 
 +  foreach ((u, vin 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 (sourcenode) 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(sourcenew_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>​ </​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| \\
  
-Bucla principală for poate fi înlocuită cu o buclă while, în care se verifică dacă în MuchiiAMA există mai puţin de |V| - 1 muchii, pentru că orice arbore de acoperire are |V| - 1 muchii, iar la fiecare pas se adaugă o muchie sigură. 
-  
  
-===== Exemplu de rulare ​=====+  * ''​%%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$
  
-Se consideră graful ​ din figura următoare:+|node|1|2|3|4|5| \\ 
 +|d_dijkstra[node]|2|2|1|2|0| \\
  
-Fiecare subarbore va fi colorat diferit. Cum iniţial fiecare nod reprezintă un subarbore, nodurile au culori diferite. Pe măsură ce subarborii sunt uniţi, nodurile aparţinând aceluiaşi subarbore vor fi coloraţi identic. Costurile muchiilor sunt sortate în ordine crescătoare. 
  
-{{ pa:​laboratoare:​92.jpg ​|}}+|node|1|2|3|4|5| \\ 
 +|d[5][node]|3|-3|-1|4|0| \\
  
-**Pas 1** 
  
-Se alege prima muchie, (1,4). Se observă că uneşte subarborii {1} şi {4}, deci muchia e adăugată la MuchiiAMA, iar cei doi subarbori se unesc. +  * STOP! Am obținut toate distanțele $d[u][v]$ cerute!
-{{ pa:​laboratoare:​93.jpg |}} +
-MuchiiAMA = {(1,4)}.+
  
-**Pas 2**+</​spoiler>​ \\
  
-Următoarea muchie este (7,8), care uneşte {7} şi {8}. Se adaugă la MuchiiAMA şi se unesc cei doi subarbori. 
-{{ pa:​laboratoare:​94.jpg |}}  
-MuchiiAMA = {(1,​4),​(7,​8)}. 
  
-**Pas 3**+==== Complexitate ====
  
-Următoarea muchie este (5,6), care uneşte {5} şi {6}. Se adaugă la MuchiiAMA şi se unesc cei doi subarbori. +  * **complexitate temporală**: $T = O(n * m * log (n))\ sau\ O(|V| * |E| * log (|V|))$ 
-{{ pa:​laboratoare:​95.jpg ​|}}  +  * **complexitate spațială** : $S O(n + m)\ sau \ O(|V| + |E|)$
-MuchiiAMA ​{(1,4),(7,8),(5,6)}.+
  
-**Pas 4**+<spoiler Detalii (analiză + optimizări)>​
  
-Următorul cost este 4. Se observă că muchiile ​(1,2şi (2,4au costul 4 şi unesc {2} cu {1,4}Se adaugă la MuchiiAMA una dintre cele două muchii, fie ea (1,2), şi se unesc cei doi subarbori. Alegerea muchiei ​(2,4va duce la găsirea unui alt AMA[Am spus anterior că un graf poate avea mai mulţi arbori minimi ​de acoperirecu acelaşi cost, dacă există muchii diferite ​cu acelaşi cost.] +  * **complexitate temporală**: 
-{{ pa:​laboratoare:​96.jpg |}}  +    * **ComputeH**:​ 
-MuchiiAMA = {(1,4),(7,8),(5,6),(1,2)}.+      * 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^* log n + n * m)$ complexitatea pentru ultima etapă. Complexitatea finală este $O(n ^ 2 log (m) + n * m)$.
  
-**Pas 5**+</​spoiler>​ \\
  
-Următoarea muchie de cost minim este (5,8), care uneşte {5,6} şi {7,8}. Se adaugă la MuchiiAMA şi se unesc cei doi subarbori, rezultând {5,6,7,8}. 
-{{ pa:​laboratoare:​97.jpg |}}  
-MuchiiAMA = {(1,​4),​(7,​8),​(5,​6),​(1,​2),​ (5,8)}. 
  
-**Pas 6**+===== TLDR =====
  
-Muchia (5,7), care are cel mai mic cost actual, are ambele extremităţi ​în subarborele {5,6,7,8}În consecinţănu se efectuează nicio schimbare.+  * 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))$.
  
-MuchiiAMA ​{(1,​4),​(7,​8),​(5,​6),​(1,​2),​(5,​8)}.+===== Exerciții =====
  
-**Pas 7** 
  
-Următorul cost este 7. Se observă că muchiile (1,6) şi (4,5) au costul 7 şi unesc subarborii {1,2,4} şi {5,6,7,8}. Se adaugă la MuchiiAMA (1,6), şi se unesc cei doi subarbori. Alegerea muchiei (4,5) va duce la găsirea unui alt AMA. +<​note>​
-{{ pa:​laboratoare:​98.jpg |}}  +
-MuchiiAMA = {(1,​4),​(7,​8),​(5,​6),​(1,​2),​(5,​8),​(1,​6)}.+
  
-**Pas 8**+Scheletul de laborator se găsește pe pagina [[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​skel/​lab10|pa-lab::​skel/​lab10]].
  
-Muchia (4,6) de cost 8 are capetele în acelaşi subarbore, deci nu se produc schimări.+</​note>​ 
 +<note warning>
  
-MuchiiAMA = {(1,4),​(7,​8),​(5,​6),​(1,​2),​(5,​8),​(1,​6)}.+Înainte de a rezolva exercițiileasiguraț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]].
  
-**Pas 9**+Prin citirea acestor precizări vă asigurați că:
  
-Muchia (1,3) de cost 9 uneşte cei doi subarbori rămaşi, {1,​2,​4,​5,​6,​7,​8} ş{3}. Deci după unire obţinem un singur arbore. (1,3) se adaugă la MuchiiAMA, care va conţine acum 7 muchii, iar algoritmul se opreşte.  +  * știț**convențiile** folosite 
-{{ pa:​laboratoare:​91.jpg |}}  +  * evitaț**buguri** 
-Arborele minim de acoperire obţinut este {(1,​4),​(7,​8),​(5,​6),​(1,​2),​(5,​8),​(1,​6),​ (1,​3)}.Costul său se calculează însumând costurile tuturor muchiilor:+  * evitați **depunctări** la lab/​teme/​test
  
-Cost(MuchiiAMA) = 1 + 2 + 3 + 4 + 5 + 7 + 9 = 31  
  
-Alţi arbori minimi de acoperire pentru exemplul propus sunt: +</​note>​
-* {(1,​4),​(7,​8),​(5,​6),​(1,​2),​(5,​8),​(4,​5),​ (1,3)} +
-* {(1,​4),​(7,​8),​(5,​6),​(2,​4),​(5,​8),​(1,​6),​ (1,3)} +
-* {(1,​4),​(7,​8),​(5,​6),​(2,​4),​(5,​8),​(4,​5),​ (1,3)}.+
  
-Pentru alte exemple explicate consultaţi [2], [3] şi [5]. +==== Roy-Floyd ​====
-===== Complexitate =====+
  
-Iniţializările se fac în O(|V|)Bucla principală while se execută de |V| ori. Procedura GetMin() ​are nevoie de un timp de ordinul O(lg|V|), deci toate apelurile vor dura O(|V|lg|V|). Bucla for este executată în total de O(|E|) ori, deoarece suma tuturor listelor de adiacenţă este 2|E|. Modificarea distanţei, a predecesorului,​ şi refacerea heapului se execută într-un timp de O(1), O(1) şi respectiv O(lg|V|). Deci în total bucla interioară for durează O(|E|lg|V|).+Se dă un graf **orientat** cu **n** noduriGraful ​are **costuri strict pozitive**.
  
-În consecinţă, timpul total de rulare este O(|V|lg|V|+|E|lg|V|),​ adică O(|E|lg|V|). Aceeaşi complexitate s-a obţinut şi pentru algoritmul Kruskal. Totuşitimpul de execuţie al algoritmului Prin se poate îmbunătăţi până la O(|E|+|V|lg|V|)folosind heap-uri Fibonacci.+Se dă matricea ponderilor ​**w**, se cere matricea drumurilor minime - **d**aplicând algoritmul **Roy-Floyd**.
  
-===== Concluzii ===== 
  
-Un arbore minim de acoperire al unui graf este un arbore care conţine toate nodurile, şi în plus acestea sunt conectate prin muchii care asigură un cost total minim. Determinarea unui arbore minim de acoperire pentru un graf este o problemă cu aplicaţii în foarte multe domenii: reţele, clustering, prelucrare de imagini. Cei mai cunoscuţi algoritmi, Prim şi Kruskal, rezolvă problema în timp polinomial. Performanţa algoritmilor depinde de modul de reprezentare a structurilor de date folosite. ​+<note warning>
  
-===== Referinţe =====+Restricții și precizări:
  
-[1] – [[http://en.wikipedia.org/​wiki/​Minimum_spanning_tree]]+  * $ 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
  
-[2] – T. Cormen, C. Leiserson, R. Rivest, C. Stein – Introducere în Algoritmi, cap. 24 
  
-[3] – [[http://​en.wikipedia.org/​wiki/​Kruskal%27s_algorithm]]+</note>
  
-[4] – [[http://​en.wikipedia.org/​wiki/​Prim%27s_algorithm]]+==== Johnson ====
  
-[5] – [[http://w3.cs.upt.ro/​~calin/​resources/​sdaa/​kruskal.ppt]]+Se dă un graf **orientat** cu **n** noduriGraful are **costuri oarecare** (pot fi și negative).
  
-[6] – [[http://​www.cs.upt.ro/​~calin/​resources/​sdaa/​prim.ppt]]+Se dă lista de adiacență cu costurile aferente, se cere matricea drumurilor minime - **d**, aplicând algoritmul **Johnson**.
  
-[7] – [[http://​www.cs.princeton.edu/​~wayne/​kleinberg-tardos/​04mst.pdf]] 
  
-[8] – [[http://​hc.ims.u-tokyo.ac.jp/​JSBi/​journal/​GIW01/​GIW01F03.pdf]]+<note warning>
  
-[9] – [[http://​www4.ncsu.edu/​~zjorgen/​ictai06.pdf]]+Restricții și precizări:
  
-[10] – CGiumale – Introducere în Analiza Algoritmilorcap.5.5+  * $ 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
  
  
-====== Probleme ======+</​note>​
  
-==== 1. Buncar (8p) ====+==== BONUS ====
  
-Datorita miscarilor politice la nivel inaltGigel, dictatorul Bitlandiei, doreste sa isi construiasca un <​del>​palat</​del>​ buncar antinuclear. Buncarul este format din N camere conectate prin coridoare. Coridoarele dintre camere sunt destul de scumpe de construit asa ca Gigel doreste sa construiasca cat mai putine si cat mai ieftine astfel incat tot sa aiba acces in toate camerele. El va da planuri si voi trebuie sa folositi 2 algoritmi diferiti (Prim [4p] si Kruskal [4p]) pentru a determina care este cea mai buna alegere de coridoare.+La acest laboratorasistentul ​va alege 1-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]]
  
-==== 2. Generarea aleatoare a unui labirint (2p) ====+===== Referințe =====
  
-Pornind de la un algoritm AMA se cere să se contruiască aleator un labirint care suportă un drum de ieșire din orice locație interioarăUlteriortrebuie să găsiți drumul spre ieșire dintr-o poziție dată folosind o parcurgere DFS.+[0] Chapters **Single-Source Shortest Paths** / **All-Pairs Shortest Paths**, “Introduction to Algorithms”,​ Thomas HCormenCharles E. Leiserson, Ronald L. Rivest and Clifford Stein.
  
pa/laboratoare/laborator-09.1366388585.txt.gz · Last modified: 2013/04/19 19:23 by constantin.tudorica1305
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