Differences

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

Link to this comparison view

pa:laboratoare:laborator-10 [2016/05/08 02:02]
traian.rebedea [Networking (8 pct)]
pa:laboratoare:laborator-10 [2023/03/15 16:55] (current)
radu.nichita
Line 1: Line 1:
-====== Laborator 10 - Flux Maxim ======+====== Laborator 10: Arbori minimi de acoperire ​====== 
 + 
 + 
 +{{:​pa:​new_pa:​partners:​bitdefender-logo.png?​190 |}} Bitdefender provides cybersecurity solutions with leading security efficacy, performance and ease of use to small and medium businesses, mid-market enterprises and consumers. Guided by a vision to be the world’s most trusted cybersecurity solutions provider, Bitdefender is committed to defending organizations and individuals around the globe against cyberattacks to transform and improve their digital experience.
  
 ===== Obiective laborator ===== ===== Obiective laborator =====
  
-  ​*formalizarea noțiunilor de rețea de transport ​și flux în rețea +În acest laborator vom introduce contextul pentru **minimum spanning tree problem** și vom studia algoritmi care pot rezolva această problemă. 
-  *prezentarea unei metode de rezolvare a problemei ​de flux maxim + 
-  *analiza unei implementări ​metodei oferite+  * Prezentarea ​problemei ​(diverse variante). 
 +  * Prezentarea algoritmilor pentru calcul ​unui arbore minim de acoperire.
  
 ===== Importanţă – aplicaţii practice ===== ===== Importanţă – aplicaţii practice =====
  
-Un graf orientat poate fi utilizat ​pentru ​modelarea unui proces ​de transport într-o rețea între un producător //s// și un consumator //t//Destinația nu poate consuma mai mult decât se produce, iar cantitatea trimisă pe o cale nu poate depăși capacitatea sa de transport.+Algoritmii ​pentru ​determinarea unor arbori (minimi) ​de acoperire au multiple aplicații practiceCâteva exemple de aplicații sunt:
  
-Rețelele de transport pot modela curgerea lichidului în sisteme cu țevi, deplasarea pieselor pe benzi rulante, deplasarea curentului prin rețele electricetransmiterea informațiilor prin rețele de comunicare etc.+  * Designul circuitelor electronice:​ 
 +    * Maparea pinilor pe un circuit astfel încât să se foloseacă o lungime minimă de traseu. 
 +  * Rețele de calculatoare:​ 
 +    * Interconectarea mai multor stații în rețeacu un cost / latență redus(ă). 
 +    * STP Protocol: protocol care previne apariția buclelor într-un LAN. 
 +  * Segmentarea imaginilor:​ 
 +    * Împărțirea unei imagini în regiuni cu proprietăți asemănătoare. 
 +    * [[https://​en.wikipedia.org/​wiki/​Minimum_spanning_tree-based_segmentation | Minimum spanning tree-based segmentation]]. 
 +  * Clustering:​ 
 +    * [[https://​en.wikipedia.org/​wiki/​Single-linkage_clustering|Single-linkage clustering]].
  
-===== Descrierea problemei şi a rezolvărilor ​=====+===== Minimum spanning tree problem ​=====
  
-O problemă des întâlnită într-o rețea de transport este cea a găsirii fluxului maxim posibil prin arcele rețelei astfel încât:+Puteți consulta capitolul **Minimum Spanning Trees** din **Introduction to Algorithms** [0] pentru mai multe definiții formale. Această secțiune sumarizează principalele notații folosite în laboratoarele de PA.
  
-1să nu fie depășite capacitățile arcelor+Cele mai uzuale notații din laboratoarele de grafuri sunt descrise în [[https://​ocw.cs.pub.ro/​courses/​pa/​skel_graph|Precizări laboratoare 07-12]] (ex. $n$, $m$, $adj$, $adj\_trans$,​ $(x, y)$, etc).
  
-2. fluxul să se conserve ​în drumul său de la //s// la //t//+Vom adăuga alte notații ​în continuarea celor introduse anterior.
  
-**Definiție 1** 
  
-O rețea de transport este un graf orientat ''​G = (V,​E)''​ cu proprietățile:​ 
  
-1. există două noduri speciale în ''​V''​//s// este nodul sursă (sau producătorul) ​și //t// este nodul terminal (sau consumatorul).+> **Arbore de acoperire** / **spanning tree**: Într-un graf neorientat **conex** $G = (V, E)$, cu funcția de cost $wE -> W$, numim **un arbore de acoperire** un subgraf al lui **G** cu număr minim de muchii ​și care interconectează toate nodurile din graf.
  
-2. este definită o funcție totală de capacitate ''​c:​ V×V → R+''​ astfel încât:+<spoiler Exemplu>
  
-  * ''​c (u,v) = 0''​ dacă ''​(u,​v) ∉ E''​ +{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab11-spanning-tree-example.png?​800| Arbore de acoperire }}
-  * ''​c (u,v) ≥ 0''​ daca ''​(u,​v) ∈ E''​+
  
-3. pentru orice nod ''​v ∈ V \ {s,t}''​ există cel puțin o cale ''​s ---> v ---> t''​.+În exemplul atașatavem un graf **neorientat** și **conex** cu următoare configurație:
  
-**Definiție 2**+  ​''​%%n = 5%%'',​ ''​%%m = 5%%''​ 
 +  ​Pentru acest exemplu, avem **3** arbori de acoperire evidențiați în aceeași figură (rândul 2).
  
-Numim flux în rețeaua ''​G = (V,E )''​ o funcție totală ''​fV×V → R''​ cu proprietățile:+Observație: Un graf **conex** are cel puțin un arbore de acoperire!
  
-1. Restricție de capacitate:​ +</​spoiler>​ \\
-  * ''​f(u,​v) ≤ c(u,v), ∀(u,v) ∈ V''​ - fluxul printr-un arc nu poate depăși capacitatea acestuia+
  
-2. Antisimetrie:​ 
-  * ''​f(u,​v) = -f(v,u) , ∀u ∈ V, ∀v ∈ V''​ 
  
-3. Conservarea fluxului: 
-  * ''​Σ f(u,v) = 0, ∀u ∈ V ∖ {s,t}, v ∈ V''​ 
  
-Un flux negativ de la u la v este unul virtual, el nu reprezintă un transport efectiv, ci doar sugerează că există un transport fizic de la v la u (este o convenție asemănătoare cu cea făcută pentru intensitățile curenților într-o rețea electrică). Ultima proprietate ne spune că la trecerea printr-un nod fluxul se conservă: suma fluxurilor ce intră într-un nod este 0 (ținând cont de convenția de semn stabilită). ​ 
  
-Numim **capacitate reziduală** a unui arc+**Pădure de arbori de acoperire** / **spanning tree forest**: Se definește similar, dar pentru graf neorientat **neconex**. Fiecare componentă conexă are un **arbore de acoperire** / **spanning tree**. Spunem că acești arbori formează împreună o **pădure** (**forest**).
  
-''​c<sub>f</​sub>​ (u,v) = c(u,v) - f(u,​v)''​+<spoiler Exemplu>
  
-și o interpretăm ca fiind cantitatea de flux adițional care poate fi transportat de la //u// la //v//, fără a +{{https://ocw.cs.pub.ro/courses/_media/pa/new_pa/lab11-spanning-forest-example.png?​800| Pădure de arbori de acoperire }}
-depăși capacitatea ''​c(u,​v)''​.+
  
-Exemplu:+În exemplul atașat, avem un graf **neorientat** și **neconex** cu următoare configurație:
  
-{{ :​pa:​laboratoare:​101.png?​350 |}} +  * ''​%%n 6%%'',​ ''​%%m 6%%''​ 
-  +  * În figura următoare evidențăm toate pădurile de arbori de acoperire - 9 pe acest exemplu. 
-Daca avem arcul ''​(u,v) ∈ V''​ cu ''​c(u,​v) ​15'' ​și ''​f(u,v) = 10''​, se pot transporta ''​c<​sub>​f</​sub>​(u,​v) ​5'' ​unități suplimentare fără a încălca restricția de capacitateDar, conform definiției, ​deși arcul ''​(v,​u) ∉ V''​ vom avea totuși o capacitate reziduală ''​c<​sub>​f</​sub>​(v,​u) ​c(v,u) – f(v,u) = 0 − (−10) = 10'':​ as putea transporta ''​10''​ unități în sens opus care să le anuleze pe cele 10 ale fluxului direct pe muchia ''​(u,​v)''​.+    * Putem elimina în 3 moduri câte o muchie din prima componentă conexă - deci 3 arbori posibili. 
 +    * Putem elimina în 3 moduri câte o muchie din doua componentă conexă - deci 3 arbori posibili. 
 +    * Numărul ​de păduri este $3 * 3 =9$ (combinăm oricare 2 arbori corespunzători componentelor conexe diferite).
  
-**Definiție 3**+Observație: Un graf **neconex** are cel puțin o pădure de arbori de acoperire!
  
-Fie o rețea de flux ''​G = (V,​E)'',​ iar //f// fluxul prin ''​G''​. Numim rețea reziduală a lui ''​G'',​ indusă de //f//, o rețea de flux notată cu ''​G<​sub>​f</​sub>​ = (V, E<​sub>​f</sub>)'',​ astfel încât+</spoiler\\
  
-  * ''​E<​sub>​f</​sub>​ = {(u,v) ∈ V ∣ c<​sub>​f</​sub>​(u,​v) = c(u,v) − f(u,v) > 0}''​ 
  
-Este important de observat că ''​E<​sub>​f</​sub>''​ și ''​E''​ pot fi disjuncte: un arc rezidual ''​(u,​v)''​ apare în rețeaua reziduală doar dacă capacitatea sa este strict pozitivă (ceea ce nu implică existența arcului în rețeaua originală). 
  
-Un drum de ameliorare este o cale ''​(u1,​ u2, ..., uk)'',​ unde ''​u1 = s''​ și ''​uk = t'',​ în graful rezidual cu ''​c<​sub>​f</​sub>​(ui,​ ui+1) > 0, ∀i=1,​2,​…,​k−1''​. Practic, un drum de ameliorare va reprezenta o cale în graf prin care se mai poate pompa flux adițional de la sursa la destinație. 
  
-Așa cum era de intuit, capacitatea reziduală a unui drum de ameliorare ​este cantitatea maximă de flux ce se poate transporta ​de-a lungul lui:+> **Arbore minim de acoperire** (**AMA**)/ **minimum spanning tree** (**MST**): Un arbore de acoperire este **ȘI** arbore minim de acoperire dacă costul total al muchiilor din arbore este minim posibil. Analog se poate defini ​și noțiunea ​de **pădure de arbori minimi de acoperire** (pornind de la cea de pădure de arbori ​de acoperire).
  
-  * ''​c<sub>f</​sub>​(p) = min{c<​sub>​f</​sub>​(u,​v) ∣ (u,v) ∈ p}''​+<spoiler Exemplu>
  
-Acum că am introdus noțiunile necesare pentru formalizarea problemei ​de flux maxim într-un ​graf, putem să prezentăm și cea mai utilizată metodă de rezolvare.+{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab11-minimum-spanning-tree-example.png?​900| Exemplu funcție de cost pentru ​graf orientat}}
  
-==== Algoritmul Ford-Fulkerson ====+În exemplul atașat, avem un graf **neorientat** și **conex** cu următoare configurație:​
  
-Aceasta este o metodă iterativă de găsire a fluxului maxim într-un graf care pleacă de la ideea: cât timp mai există un drum de ameliorare (o cale de la sursă la destinație) pot pompa pe această cale un flux suplimentar egal cu capacitatea reziduală a căii.+  * ''​%%n = 5%%'',​ ''​%%m = 5%%''​ 
 +  * În figura următoare evidențăm toți arborii ​de acoperire. Doar 2 dintre aceștia au cost minim **5**.
  
-Acest algoritm ​reprezintă mai mult un șablon de rezolvare ​pentru ​că nu detaliază modul în care se alege drumul de ameliorare ​din rețeaua reziduală.+Observație:​ Un graf **conex** are cel puțin un arbore minim de acoperire! 
 + 
 +</​spoiler>​ \\ 
 + 
 + 
 +===== Algoritmi ===== 
 + 
 +Pentru **minimum spanning tree problem** există mai mulți algoritmi, dintre care amintim: 
 + 
 +  * **Kruskal**:​ abordare greedy care se bazează pe sortarea muchiile după cost. Mai multe detalii în **Introduction to Algorithms** [0]. 
 +  * **Prim**: abordare greedy care extinde arborele căutat pornind de la o rădăcină (nod ales oarecare). Mai multe detalii în **Introduction to Algorithms** [0]. 
 +  * **Karger, Klein & Tarjan**: ​algoritm ​randomizat cu complexitate liniară (mai bună decât Kruskal ​și Prim). Mai multe detalii în **A Randomized Linear-Time Algorithm to Find Minimum Spanning Trees** [1]. 
 +  * **Bernard Chazelle**: algoritm determinist cu o complexitate liniară (cu complexitate mai bună decât soluția anterioară). Mai multe detalii în **A Minimum Spanning Tree Algorithm with Inverse Ackermann Type Complexity** [2]. 
 + 
 +În acest laborator vom studia și vom implementa **algoritmul lui Kruskal**. De asemenea, oferim ca studiu ​de caz pentru ​acasă, un material pentru algoritmul lui Prim. 
 + 
 +===== Kruskal ===== 
 + 
 +Algoritmul lui [[https://​en.wikipedia.org/​wiki/​Joseph_Kruskal|Joseph Bernard **Kruskal**]] (**Kruskal’s algorithm**) rezolvă **minimum spanning tree problem** ​în grafuri neorientate **G = (V, E)** cu costurile muchiilor **oarecare** aplicând o strategie greedy foarte simplă: muchiile de cost minim probabil fac parte din MST! 
 + 
 +==== Kruskal - Pseudocod ==== 
 + 
 + 
 +<​note>​ 
 + 
 +Algoritmul lui Kruskal folosește o structură de date care suportă 2 operații:​ 
 + 
 +  * În ce mulțime este elementul **x**? 
 +  * Să se reunească mulțimile ​din care fac parte elementele **x** și **y**. 
 + 
 +Se pot folosi mai multe structuri de date. Pentru o implementare eficientă, alegem **DisjointSet**. Vă recomandăm să parcurgeți [[https://​infoarena.ro/​problema/​disjoint | DisjointSet]]. **ATENȚIE!** Scheletul de laborator oferă o astfel de implementare. 
 + 
 + 
 +</​note>​
  
 <code cpp> <code cpp>
-Ford_Fulkerson +// apply Kruskal'​s algorithm for computing a Minimum Spanning Tree (MST). 
-    ​Input ​G(V,E), s, t +// 
-    ​Output |fmax| +// nodes     = list of all nodes from G 
-    ​|fmax| ← 0 +// edges     = the list of all edges in G 
-    f{u,v← 0, ∀(u,v) ∈ V×V +//             ​example:​ edge (nodeneigh, weight) 
-    while ∃path p(s ---> tin Gf such that cf(u,v> 0, ∀(u,v) ∈ p +// 
-        find cf(p= min{cf(u,v) | cf(u,v∈ p} +// returns: costmst 
-        |fmax| +cf(p+//          cost = the cost of the MST 
-        ​for-each ​(u,v∈ p +//          mst = the actual set of edges in MST 
-            f(u,v) ← f(u,v) + cf(p) +// 
-            f(v,u) ← −f(u,v+Kruskal(G=(nodesedges)) { 
-    ​return |fmax|+  // STEP 0: initialize results 
 +  cost = 0; // cost of the built MST 
 +  mst = {}; // the actual set of edges (u, v) in the built MST 
 + 
 +  // STEP 1: initialize disjoint set data structure 
 +  // (tree is created for each node) 
 +  disjointset = DisjointSet(nodes)
 + 
 +  // STEP 2: 
 +  sort(edgescompare=nondecreasing order by weight)
 + 
 +  // STEP 3: Add edge by edge to MST if no cycles are created. 
 +  foreach ( (u, v, win edges ) { 
 +    // STEP 3.1: Check if anv are in different trees. 
 +    if (disjointset.setOf(u) !disjointset.setOf(v)) { 
 +      // STEP 3.2: Merge these 2 trees (no cycles created). 
 +      ​disjointset.union(u, v)
 + 
 +      // STEP 3.3: Extend MST with the current edge. 
 +      cost += w; 
 +      mst += { (u, v) }; 
 +    } 
 +  } 
 + 
 +  return costmst; 
 +
 + 
 +// Usage example: 
 +cost, mst = Kruskal(G=(nodesedges)); 
 +// 1. Use cost of MST. 
 +// 2. Use edges of MST (e.g. actually build the tree).
 </​code>​ </​code>​
 +Algoritmul lui Kruskal pornește cu structura de date Păduri de mulțimi disjuncte inițializată cu n noduri izolate. Muchiile sunt sortate crescător după cost și se încearcă adăugarea lor, rând pe rând la pădurea de arbori.
  
-Complexitatea va fi ''​O(E ​f max)''​ pentru că în ciclul while putem găsiîn cel mai rău cazdoar cai care duc la creșterea fluxului cu doar o unitate la fiecare pas.+  ​Dacă o muchie $(u, v)$ are capetele ​în 2 arbori diferiți, atunci prin adăugarea acesteianu vom crea ciclu, ci vom crea un arbore ​mai mare (din cei 2 mici reuniți). 
 +  * Altfel, nu putem adăuga muchiadeoarece am crea un ciclu. Această muchie se ignoră.
  
-Ne punem acum problema dacă acest algoritm este corect, dacă la final vom avea cu adevărat fluxul maxim posibil prin graf. Corectitudinea algoritmului derivă imediat din teorema **Flux maxim - tăietura minimă**.+==== Exemple ====
  
-Numim o **tăietură a unui graf** o partiție ''​(S,​T)''​ a nodurilor sale cu proprietatea ''​s ∈ S''​ si ''​t ∈ T''​. ​+=== Exemplu Kruskal ===
  
-**Teorema flux maxim – tăietura minimă**+{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab11-kruskal.png?​900| Exemplu Kruskal}}
  
-Pentru o rețea de flux ''​G(V,E)''​ următoarele afirmații sunt echivalente:​+Un **MST** găsit cu algoritmul lui Kruskal este: ${ (12); (2, 4); (2, 3); (3, 5)}$ de cost **5**.
  
-1. ''​f''​ este fluxul maxim în ''​G''​+<spoiler Explicație pas cu pas>
  
-2. Rețeaua reziduală ''​G<​sub>​f</​sub>''​ nu conține drumuri de ameliorare+În exemplul atașat, avem un graf **neorientat** cu următoare configurație:
  
-3. Există o tăietură ​''​(S,T)'' ​a lui ''​G'' ​astfel încât fluxul net prin tăietură este egal cu capacitatea acelei tăieturi.+  * ''​%%n = 5%%'',​ ''​%%m = 5%%''​ 
 +  * Funcția de cost ''​%%w%%''​ are valorile menționate pe muchii. 
 +  * Muchiile sortate după cost sunt: 
 +    * $(3, 5)$ de cost $-1$ 
 +    * $(2, 4)$ de cost $1$ 
 +    * $(2, 3)$ de cost $2$ 
 +    * $(2, 5)$ de cost $2$ 
 +    * $(1, 2)$ de cost $3$ 
 +  * Explicație pas cu pas 
 +    * STEP 0: Inițializăm pădurile de mulțimi disjuncte - pornind cu n arbori (noduri izolate). 
 +    * STEP 1: Muchia cu costul cel mai mic care e nefolosită este $(3, 5)$ de cost -1. Se adaugă la **MST**. Se reunesc 2 arbori. 
 +    * STEP 2: Muchia ​cu costul cel mai mic care e nefolosită este $(2, 4)$ de cost 1. Se adaugă la **MST**. Se reunesc 2 arbori. 
 +    * STEP 3: Muchia cu costul cel mai mic care e nefolosită este $(2, 3)$ de cost 2. Se adaugă la **MST**. Se reunesc 2 arbori. 
 +      * Observație:​ În acest pas am fi putut alege muchia $(2, 5)$ cu același cost. 
 +    * STEP 4: 
 +      * Muchia $(2, 5)$ nu va fi folosită deoarece are capetele în același arbore. 
 +      * Muchia cu costul cel mai mic care e nefolosită este $(1, 2)$ de cost 3. Se adaugă la **MST**. Se reunesc 2 arbori. 
 +    * Avem un arbore. STOP.
  
-**Obs:** Prin orice tăietură fluxul este egal cu cel maxim pentru că nu există o altă cale pe care ar putea ajunge flux de la sursă la destinație ​și care să nu treacă prin tăietură (ar încălca tocmai definiția ei); saualtfel spusvaloarea unui flux într-o rețea este dată de fluxul oricărei tăieturi. Astfelfluxul total va fi mărginit de cea mai mică capacitate a unei tăieturi. Dacă este îndeplinit punctul 3. al teoremei atunci ​știm că acea tăietură nu poate fi decât una de capacitate minimă. Ultima incercare de a gasi o cale de la sursa la drena va rezulta in gasirea doar a elementelor marginite de o astfel de taietura.+ObservațieÎn STEP 3 pas am fi putut alege muchia $(2, 5)$ cu același cost. Obțineam un MST care diferea printr-o singură muchie ​({${ (1, 2); (25); (23); (35)}}$), dar cu același cost **5**.
  
-Exemplu:+</​spoiler>​ \\
  
-Rețeaua inițială: 
-{{ :​pa:​laboratoare:​102.png?​350 |}} 
  
-Rețeaua reziduală:​ +==== Complexitate ====
-{{ :​pa:​laboratoare:​103.png?​350 |}}  +
  
-Observăm că deși muchia ''​(d,​c)''​ are capacitate 0 în rețeaua originală ​(ea nu ar putea transporta fluxîn rețeaua reziduală avem ''​c(d,​c) = 1''​ ceea ce îi permite să facă parte din drumul de ameliorare ''​p1 ​= (s, a, b, d, c, t)''​ de capacitate ''​c<​sub>​f</​sub>​(p1) = 1'',​ astfel că adăugarea acestui flux suplimentar pe muchia ''​(d,​c)''​ nu va duce la încălcarea restricției de capacitate; sau am fi putut alege drumul ''​p2=(s,​ a, c, t)''​ cu ''​c<​sub>​f</​sub>​(p2) = 1''​ sau ''​p3 = (s,​a,​b,​d,​t)''​ cu ''​c<​sub>​f</​sub>​(p3) = 1''​. +  * **complexitate temporală**: $T = O(m * log m)\ sau\ O(|E| * log |E|)
-Performanța algoritmului ține de modul în care va fi ales drumul de ameliorare, se poate întâmpla ca pentru ''​|fmax|''​ de valoarea mare o alegere nepotrivită să ducă la timpi de execuție foarte mari. +  * **complexitate spațială** : $S O(n)$
  
-==== Implementarea Edmonds-Karp ====+<spoiler Detalii (analiză + optimizări)>​
  
-Așa cum am văzut, algoritmul Ford-Fulkerson nu definește o metodă de alegere a drumului de ameliorare pe baza căruia se modifică fluxul în grafImplementarea Edmonds-Karp alege întotdeauna cea mai scurtă cale folosind ​căutare în lățime în graful rezidual unde fiecare arc are ponderea 1. Se poate demonstra că lungimea căilor găsite astfel crește monoton ​cu fiecare nouă ameliorare.+  * **complexitate temporală**: 
 +    * Se sortează cele **m** muchii în ordine crescătoare după cost - $O(m log m)$. 
 +    * Se folosesc **n** operații pe **DisjointSet** ​$O(n log_{*}n)$, care poate fi aproximat cu $O(n)$ (demonstrație pe pagina **DisjointSet**). 
 +      * ATENȚIE! Complexitatea conține funcția logaritm iterat, nu logaritm ([[https://​en.wikipedia.org/​wiki/​Iterated_logarithm | Iterated logarithm]]),​ care pentru valorile uzuale din problemele de algoritmică poate fi aproximată cu constantă foarte mică
 +  * **complexitate spațială** : Se ține o structură de date **DisjointSet** cu maximum **n** noduri. 
 + 
 +</​spoiler>​ \\ 
 + 
 + 
 +===== [Studiu de caz] Prim ===== 
 + 
 +Algoritmul lui [[https://​en.wikipedia.org/​wiki/​Robert_C._Prim|Robert C **Prim**]] (**Prim’s algorithm**) rezolvă **minimum spanning tree problem** în grafuri neorientate **G = (V, E)** cu costurile muchiilor **oarecare** aplicând o strategie constructivă greedy, asemănătoare cu algoritmul lui Dijkstra: merge pe muchiile de cost minim, din aproape în aproape, considerând o sursă inițial aleasă aleator ​și extinzând MST-ul curent ​cu muchia de cost minim neadăugată încă la arbore. 
 + 
 +==== Prim Pseudocod ==== 
 + 
 +<spoiler Prim - Pseudocod>​
  
 <code cpp> <code cpp>
-Edmonds-Karp +// apply Prim's algorithm for computing a Minimum Spanning Tree (MST). 
-    Input G(V,E), s, t +// 
-    ​Output |fmax| +// source ​   = source / starting node for computing / expading MST 
-    ​|fmax| ← 0 +//             (if not specifiednode 1 is defaulted) 
-    f(u,v← 0(u,v∈ V×V +// nodes     = list of all nodes from G 
-    while true +// adj[node] = the adjacency list of node 
-        p(s ⇢ t) ← BFS(Gf,s,t+//             ​example:​ adj[node] = {..., (neighweight...} => edge (nodeneighweight
-        if not ∃p(s ⇢ t) +// 
-            ​break;​ +// returns: cost, mst 
-        find cf(p) min{cf(u,v) ∣ cf(u,v∈ p} +//          cost the cost of the MST 
-        ​|fmax| +cf(p+//          mst = the actual set of edges in MST 
-        ​for-each (u,v) ∈ p +// 
-            f(u,v) ← f(u,v) + cf(p) +Prim(source=1G=(nodesadj)) { 
-            f(v,u) ← −f(u,v+  // STEP 0: initialize results 
-        ​return |fmax| +  // d[node] ​distance from MST (any node in current/​partial MSTto node 
-</code>+  // ​p[node] = parent of node: node is connected to MST with edge p[node] - node 
 +  ​foreach ​(node in nodes{ 
 +      ​d[node] = +oo;                          // distance not yet computed 
 +      ​p[node] = null;                         // parent not yet found 
 +  }
  
-Plecând de la ideea că drumurile de ameliorare găsite au lungimi din ce în ce mai mari se poate arăta că în această implementare fluxul se mărește de cel mult ''​O(V*E)''​ ori ([1]pag.513)+  // STEP 0: initialize results 
 +  cost = 0; // cost of the built MST 
 +  mst = {}; // the actual set of edges (uvin the built MST
  
-Complexitatea algoritmului va fi ''​O(V*E<​sup>​2<​/sup>​)''​. Să luăm un exemplu de rulare al acestui algoritm. Vom considera starea rețelei după ce a fost găsita prima cale de pompare flux(inițial toate arcele sunt etichetate cu 0/0 conform notației stabilite)+  ​// STEP 1initialize a priority queue 
-  +  pq = {};
-{{ :​pa:​laboratoare:​104.png?​500 |}}+
  
-**Obs:** In cazul ultimului drum de ameliorare găsit in exemplul dat, se observa ca deși nu exista muchia ''​(d,c)''​ se simulează un flux pe aceasta printr-unul negativ in sens opus.+  // STEP 2add the source(s) into pq 
 +  ​d[source] = 0;                              // distance from source to MST 
 +  p[source] = null;                           // source never has parent 
 +  pq.push( (sourced[source]);
  
-===== Variații ale problemei clasice ===== +  // STEP 3: Build MST. 
-In rețelele clasice studiate pana acum aveam o sursa unica care putea produce oricâtdestinația unica consuma oricât, orice nod intermediar conserva fluxul, iar singura constrângere a muchiilor era limitarea superioara a fluxului prin capacitate. Sa vedem cum putem generaliza aceste condiții si daca rețelele obținute ar putea fi reduse la una clasica.+  while ( !pq.empty() ) { 
 +    // STEP 3.1: Pop next possible node to connect with MST. 
 +    node_ = pq.pop() 
 +    if (used[node]) { 
 +      continue; 
 +    }
  
-==== Surse si destinații multiple ====+    // STEP 3.2: Extend MST with edge p[node] - node 
 +    used[node] ​true; 
 +    if (p[node] !null) { 
 +      cost +d[node]; 
 +      mst +{ (node, p[node]) }; 
 +    }
  
-{{ :​pa:​laboratoare:​105.png?​350 |}}+    // STEP 3.3: relax all edges (node, neigh) 
 +    foreach ( (neigh, weight) in adj[node]) ​{ 
 +      // Can we find a better / shorter link / edge from node to current MST? 
 +      if (!used[neigh] && weight < d[neigh]) ​{ 
 +        d[neigh] = weight; ​                             // update the new distance from neigh to MST 
 +        p[neigh] = node;                                // save parent
  
-Se observă ca putem reduce acest graf la cel cunoscut prin adăugarea unei meta-surse legată de sursele mici prin muchii de capacitate nelimitata si analog un meta-terminal cu aceleași proprietăți. Global comportamentul rețelei de flux nu se va schimba.+        pq.push( (neigh, d[neigh]) );                   // replace distance for neigh in pq 
 +      } 
 +    } 
 +  }
  
-==== Cuplaj bipartit maxim ====+  return cost, mst; 
 +}
  
-Fiind dat un graf neorientat ''​G = (V,E)'',​ un cuplaj este o submultime de muchii ''​M''​ inclusa in ''​E''​ astfel incat pentru toate varfurile ''​v ∈ V'',​ exista cel mult o muchie in ''​M''​ incidenta in ''​v''​Spunem ca un varf  ''​v ∈ M''​ este cuplat de cuplajul ''​M''​ daca exista o muchie in ''​M''​ incidenta in ''​v''​Un cuplaj maxim este un cuplaj de cardinalitate maxima. In cazul grafurilor bipartitemultimea de varfuri poate fi partitionata ​in ''​V = L U R'',​ unde ''​L''​ si ''​R''​ sunt disjuncte si toate muchiile din ''​E''​ sunt intre ''​L''​ si ''​R''​. Problema poate fi rezolvata cu ajutorul notiunii de flux, construind reteaua de transport ''​G' = (V',​E'​)''​ pentru graful bipartit ''​G''​. Vom alege sursa //s// si destinatia ​//t// ca fiind noi varfuri care nu sunt in ''​V''​ si vom construi ''​V'​ = V U {s,​t}''​. Arcele orientate ale lui ''​G'''​ sunt date de:+// Usage example: 
 +cost, mst = Prim(1, ​G=(nodesedges)); // e.gsource = 1can be any node in G 
 +// 1. Use cost of MST. 
 +// 2. Use edges of MST (e.g. actually build the tree). 
 +</code> 
 +</spoiler> \\
  
-  * ''​E'​ = { (s, u) : u ∈ L } U { (u, v) : u ∈ L, v ∈ R si (u, v) ∈ E} U { (v, t) : v ∈ R}''​ 
  
-Pentru a completa constructia,​ vom atribui fiecarei muchii din E' capacitatea unitate.+==== Complexitate ====
  
-==== Rețea cu noduri ce nu conservă fluxul ====+  * **complexitate temporală**:​ $T O(m * log n)\ sau\ O(|E| * log |V|)$ 
 +  * **complexitate spațială** : $S O(n)$
  
-Spre deosebire de //s// si //t// care produc/​consumă oricât, un nod intermediar ar putea produce sau consuma o cantitate constanta de flux la trecerea prin el. In acest caz vom avea un invariant la nivel de nod care ia forma:+<spoiler Detalii (analiză + optimizări)>​
  
-  * ''​f<​sub>​in</​sub>​ − f<​sub>​out<​/sub> = di''​unde ''​di''​ este cantitatea produsă suplimentar ​(''>​ 0''​sau solicitată ​(''<​ 0''​de un nod+  * **complexitate temporală**:​ Se încearcă relaxarea tuturor celor **m** muchii din graf, analog algoritmului Dijkstra. 
 +  * **complexitate spațială** : Se ține o coadă de priorități ​un set cu maximum **n** noduri. 
 +  * **optimizare**:​ Analog Dijkstraputem să obținem: 
 +    * **Prim cu heap binar** - $O(m log n)$. 
 +    * **Prim cu heap Fibonacci** - $O(n logn + m)$.
  
-Am putea transforma egalitatea in:+</​spoiler>​ \\
  
-  * ''​(f<​sub>​in</​sub>​ + |di|) – f<​sub>​out</​sub>​ = 0''​ , dacă ''​di < 0''​ 
-  * ''​f<​sub>​in</​sub>​ − ( f<​sub>​out</​sub>​ + |di|) =  0''​ , daca ''​di > 0''​ 
  
-Altfel spus, un nod ce consumă flux poate fi transformat intr-unul ce conservă fluxul și are un in-arc adițional de capacitate ''​|di|'',​ iar unul ce produce flux va avea un out-arc de aceeași capacitate.+===== TLDR =====
  
-La nivelul unei rețele întregi se adaugă un nod sursă ​cu muchii către toate nodurile ce consumau flux si un nod destinație dinspre toate nodurile ce produceau flux+  * Pentru **minimum spanning tree problem**, am studiat 2 algoritmi (Kruskal și Prim) cu aceeași complexitate ($O(m log m)$). 
 +  * Algoritmul lui Kruskal este de preferat pentru simplitatea / intuitivitatea lui, dificultatea reducându-se la a implementa structura de date **DisjointSet**.
  
-Exemplu:+===== Exerciții =====
  
-{{ :​pa:​laboratoare:​106.png?​250 |}} 
-  
-se va transforma in: 
-  
-{{ :​pa:​laboratoare:​107.png?​250 |}} 
  
-==== Rețea cu limite inferioare de capacitate ====+<​note>​
  
-Există cazuri în care aș vrea ca datele de pe muchiile rețelei sa facă parte dintr-un anumit interval ''​[inf, sup]''​Pe o astfel de muchie fluxul trebuie să respecte inegalitatea ''​inf ≤ f ≤ sup''​+Scheletul de laborator se găsește pe pagina ​[[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​skel/​lab11|pa-lab::​skel/​lab11]].
  
-Plecând tot de la condițiile de conservare la nivel de nod putem translata intervalul ''​[inf,​ sup]''​ în ''​[0,​ sup-inf]''​ și să considerăm că nodul sursă a consumat ''​inf''​ unități de flux iar nodul destinație a produs ''​inf''​ unități. Din exterior entitatea alcătuită din doua noduri și o muchie este văzută ca acționând în același fel asupra fluxului ce o traversează.+</​note>​ 
 +<note warning>
  
-Iată un exemplu ​de transformare:+Î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]].
  
-{{ :​pa:​laboratoare:​108.png?​250 |}} +Prin citirea acestor precizări vă asigurați că:
-  +
-Bineînțeles că toate aceste transformări pot fi combinate pentru a se ajunge la rețeaua de flux clasică.+
  
-===== Concluzii ​și observații =====+  * știț**convențiile** folosite 
 +  * evitați **buguri** 
 +  * evitați **depunctări** la lab/​teme/​test
  
-Laboratorul de față s-a vrut a fi doar o introducere în domeniul fluxurilor într-un graf – modalitate de a reprezenta probleme de circulație a materialelor atât de frecvent întâlnite. In [1] și [2] găsiți și alți algoritmi interesanți împreună cu studiul complexității lor (algoritmul de pompare preflux, algoritmul „mutare-in-fata”). Spre exemplu, cel mai bun algoritm în prezent pentru cuplajul bipartit maxim se executa in ''​O(√V*E)''​. 
  
-===== Referinte =====+</​note>​
  
-[1] Introducere in algoritmi, Thomas H. Cormen, Charles E. Leiserson, Ronald R. Rivest – Capitolul VI Algoritmi pe grafuri: Flux maxim+==== Kruskal ====
  
-[2] Introducere in analiza algoritmilor,​ Cristian A. Giumale – Cap. V Algoritmi pr grafuri: +Se dă un graf **neorientat** și **conex** cu **n** noduri și **m** muchii (cu costuri oarecare pe muchii).
-Fluxuri maxime intr-un graf+
  
-[3] Un articol de la MIT: [[http://​web.mit.edu/​15.053/​www/​AMP-Appendix-C.pdf | A Labeling Algorithm for the maximum flow network problem]]+Folosiți algoritmul lui **Kruskal** pentru a găsi un **MST**.
  
-[4] Resurse wiki – +Task-uri:
-[[http://​en.wikipedia.org/​wiki/​Edmonds%E2%80%93Karp_algorithm | Edmonds Karp]] [[http://​en.wikipedia.org/​wiki/​Max-flow_min-cut_theorem | Max Flow - Min Cut Theorem]]+
  
-[5] +  - Găsiți **costul** MST. 
-[[http://​www.cs.princeton.edu/​~wayne/​cs423/​lectures/​max-flow-applications-4up.pdf | Aplicatii flux maxim]]+  - Găsiți care sunt **muchiile** din MST**ATENȚIE!** Se poate găsi orice **MST** (în caz că există mai mulți)Ordinea muchiilor din vectorul rezultat **NU** este relevantă.
  
  
-===== Probleme =====+<note warning>
  
-==== Networking (9 pct) ====+Restricții și precizări:
  
-Pornind ​de la un graf orientat conex și două noduri ​''​u'' ​și ''​v'' ​ale acestuia se cere să se determine următorele elemente: +  * $ n <= 2 * 10^5 $ 
-[6p primul punct rezolvat + 3p al doilea]+  * $ m <= 4 * 10^5 $ 
 +  * $ -10^3 <= c <= 10^3$, unde c este costul unei muchii 
 +  * timp de execuție 
 +    * C++: ''​%%1s%%''​ 
 +    * Java: ''​%%7s%%''​ 
 +  * Vă recomandăm să parcurgeți ​[[https://​infoarena.ro/​problema/​disjoint | DisjointSet]]. **ATENȚIE!** Scheletul de laborator oferă o astfel de implementare.
  
-a) Tăietura minimală a grafului afișată sub forma a unei mulțimi de cardinal minim de muchii ce trebuie eliminate pentru a deconecta ''​u''​ și ''​v''​. 
  
-b) Pentru topologia dată, afișați numărul maxim de drumuri disjuncte între ''​u''​ și ''​v'',​ dar și drumurile în sine. Două drumuri sunt considerate disjuncte dacă nu au nicio muchie în comun+</​note>​
  
-Graful din schelet:+==== BONUS ====
  
-{{ :​pa:​laboratoare:​graf_flux.png?150 |}}+La acest laborator, asistentul va alege 1-2 probleme din secțiunea extra.
  
-==== Generare de graf orientat (3 pct) ====+==== Extra ====
  
-Se dă o listă de ''​N''​ noduri, pentru fiecare cunoscându-se gradul de intrare si de ieșire al acestoraRealizați un program care să construiască un graf **orientat** ''​G''​ cu ''​N''​ noduri, care să satisfaca gradele dateNu se permite mai mult de o muchie între două noduri.\\ +  * [[https://​infoarena.ro/​problema/​desen|infoarena/​desen]] 
-Exemplu:+  ​[[https://​infoarena.ro/​problema/​radiatie|infoarena/​radiatie]] 
 +  ​[[https://​infoarena.ro/​problema/​bile|infoarena/​bile]] 
 +  * [[https://​codeforces.com/​problemsets/​acmsguru/​problem/​99999/​323|codeforces/​aviamachinations]]
  
-^ Nod ^ Grad intrare ^ Grad iesire ^ +===== Referințe ===== 
-|  1  |  1  |  3  | + 
-|  2  |  1  |  2  | +[0] Chapters **Minimum Spanning Trees**, “Introduction to Algorithms”,​ Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein. 
-|  3  |  3  |  ​ + 
-|  4  |  ​  ​1  ​|+[1] [[http://​cs.brown.edu/​research/​pubs/​pdfs/​1995/​Karger-1995-RLT.pdf ​A Randomized Linear-Time Algorithm to Find Minimum Spanning Trees]], David R. Karger, Philip N. Klein, Robert E. Tarjan. 
 + 
 +[2] [[https://​dl.acm.org/​doi/​pdf/​10.1145/​355541.355562 ​A Minimum Spanning Tree Algorithm with InverseAckermann Type Complexity|]], Bernard, Chazelle.
  
-O soluție posibilă de muchii: 
-<​code>​ 
-1 2 
-1 4 
-1 3 
-2 3 
-2 1 
-3 4 
-4 3 
-</​code>​ 
pa/laboratoare/laborator-10.1462662156.txt.gz · Last modified: 2016/05/08 02:02 by traian.rebedea
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