Differences

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

Link to this comparison view

pa:laboratoare:laborator-10 [2016/05/12 12:34]
dumitru.cercel [Generare de graf orientat (4 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!
  
-<code cpp> +</spoiler\\
-Ford_Fulkerson +
-    Input G(V,E), s, t +
-    Output |fmax| +
-    |fmax| ← 0 +
-    f{u,v) ← 0, ∀(u,v) ∈ V×V +
-    while ∃a path p(s ---> t) in Gf such that cf(u,v) > 0, ∀(u,v) ∈ p +
-        find cf(p) = min{cf(u,v) | cf(u,v) ∈ p} +
-        |fmax| += cf(p) +
-        for-each (u,v) ∈ p +
-            f(u,v) ← f(u,v) + cf(p) +
-            f(v,u) ← −f(u,v) +
-    return |fmax| +
-</code>+
  
-Complexitatea va fi ''​O(E * f max)''​ pentru că în ciclul while putem găsi, în cel mai rău caz, doar cai care duc la creșterea fluxului cu doar o unitate la fiecare pas. 
  
-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ă**.+===== Algoritmi =====
  
-Numim o **tăietură a unui graf** o partiție ''​(S,T)''​ a nodurilor sale cu proprietatea ''​s ∈ S''​ si ''​t ∈ T''​. ​+Pentru ​**minimum spanning tree problem** există mai mulți algoritmidintre care amintim:
  
-**Teorema flux maxim – tăietura minimă: **+  ​* **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].
  
-Pentru o rețea de flux ''​G(V,E)''​ următoarele afirmații sunt echivalente:​+În acest laborator vom studia și vom implementa **algoritmul lui Kruskal**. De asemeneaoferim ca studiu de caz pentru acasă, un material pentru algoritmul lui Prim.
  
-1. ''​f''​ este fluxul maxim în ''​G''​+===== Kruskal =====
  
-2Rețeaua reziduală ''​G<​sub>​f</​sub>''​ nu conține drumuri ​de ameliorare+Algoritmul lui [[https://​en.wikipedia.org/​wiki/​Joseph_Kruskal|Joseph Bernard **Kruskal**]] (**Kruskal’s algorithm**) rezolvă **minimum spanning tree problem** în grafuri neorientate **= (V, E)** cu costurile muchiilor **oarecare** aplicând o strategie greedy foarte simplă: muchiile ​de cost minim probabil fac parte din MST!
  
-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.+==== Kruskal - Pseudocod ====
  
-**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); sau, altfel spus, valoarea unui flux într-o rețea este dată de fluxul oricărei tăieturi. Astfel, fluxul 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. 
  
-Exemplu:+<​note>​
  
-Rețeaua inițială:​ +Algoritmul lui Kruskal folosește o structură de date care suportă 2 operații:
-{{ :​pa:​laboratoare:102.png?350 |}}+
  
-Rețeaua reziduală:​ +  * În ce mulțime este elementul **x**? 
-{{ :​pa:​laboratoare:​103.png?350 |}}  +  * Să se reunească mulțimile din care fac parte elementele **x** și **y**.
  
-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''​. +Se pot folosi mai multe structuri ​de date. Pentru o implementare eficientă, alegem **DisjointSet**. Vă recomandăsă parcurgeți [[https://infoarena.ro/​problema/​disjoint ​DisjointSet]]. **ATENȚIE!** Scheletul ​de laborator oferă ​astfel ​de implementare.
-Performanța algoritmului ține de modul în care va fi ales drumul de ameliorare, se poate întâmpla ca pentru ''​|fmax|'' ​de valoarea mare alegere nepotrivită să ducă la timpi de execuție foarte mari+
  
-==== Implementarea Edmonds-Karp ==== 
  
-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 graf. Implementarea Edmonds-Karp alege întotdeauna cea mai scurtă cale folosind o 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.+</​note>​
  
 <code cpp> <code cpp>
-Edmonds-Karp +// 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 true +// 
-        p(s ⇢ t← BFS(Gf,s,t+// returns: costmst 
-        if not ∃p(s ⇢ t) +//          cost = the cost of the MST 
-            break+//          mst = the actual set of edges in MST 
-        find cf(p) = min{cf(u,v) ∣ cf(u,v) ∈ p} +// 
-        ​|fmax| +cf(p+Kruskal(G=(nodesedges)) { 
-        ​for-each ​(u,v∈ p +  // STEP 0: initialize results 
-            f(u,v) ← f(u,v) + cf(p) +  cost = 0; // cost of the built MST 
-            f(v,u) ← −f(u,v+  mst = {}; // the actual set of edges (u, v) in the built MST 
-        ​return |fmax|+ 
 +  // STEP 1: initialize disjoint set data structure 
 +  // (a tree is created for each node) 
 +  disjointset = DisjointSet(nodes); 
 + 
 +  // STEP 2: 
 +  sort(edges, compare=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.
  
-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)+  * Dacă o muchie $(u, v)$ are capetele ​în 2 arbori diferiți, atunci prin adăugarea acesteia, nu vom crea ciclu, ci vom crea un arbore mai mare (din cei 2 mici reuniți)
 +  * Altfelnu putem adăuga muchia, deoarece am crea un cicluAceastă muchie se ignoră.
  
-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):​ +==== Exemple ====
-  +
-{{ :​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.+=== Exemplu Kruskal ===
  
-===== Variații ale problemei clasice ===== +{{https://​ocw.cs.pub.ro/​courses/​_media/​pa/​new_pa/​lab11-kruskal.png?​900| Exemplu Kruskal}}
-In rețelele clasice studiate pana acum aveam o sursa unica care putea produce oricât, destinația unica consuma oricât, orice nod intermediar conserva fluxul, iar singura constrângere a muchiilor era limitarea superioara a fluxului prin capacitateSa vedem cum putem generaliza aceste condiții si daca rețelele obținute ar putea fi reduse la una clasica.+
  
-==== Surse si destinații multiple ====+Un **MST** găsit cu algoritmul lui Kruskal este: ${ (1, 2); (2, 4); (2, 3); (3, 5)}$ de cost **5**.
  
-{{ :​pa:​laboratoare:​105.png?​350 |}}+<spoiler Explicație pas cu pas>
  
-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.+În exemplul atașat, avem un graf **neorientat** ​cu următoare configurație:
  
-==== Cuplaj bipartit maxim ====+  * ''​%%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.
  
-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 fluxconstruind 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:+Observație:​ În STEP 3 pas am fi putut alege muchia $(25)$ cu același costObțineam ​un MST care diferea printr-singură ​muchie ​({${ (12); (25); (23); (35)}}$), dar cu același cost **5**.
  
-  * ''​E'​ = { (s, u) : u ∈ L } U { (u, v) : u ∈ L, v ∈ R si (u, v) ∈ E} U { (v, t) : v ∈ R}''​+</​spoiler>​ \\
  
-Pentru a completa constructia,​ vom atribui fiecarei muchii din E' capacitatea unitate. 
  
-==== Rețea cu noduri ce nu conservă fluxul ​====+==== Complexitate ​====
  
-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:+  * **complexitate temporală**: $T = O(m * log m)\ sau\ O(|E| * log |E|)$ 
 +  * **complexitate spațială** ​$S = O(n)$
  
-  * ''​f<sub>​in</​sub>​ − f<​sub>​out</​sub>​ = di'',​ unde ''​di''​ este cantitatea produsă suplimentar ​(''>​ 0''​) sau solicitată (''<​ 0''​de un nod. +<spoiler Detalii ​(analiză + optimizări)>
  
-Am putea transforma egalitatea in:+  * **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 o constantă foarte mică. 
 +  * **complexitate spațială** : Se ține o structură de date **DisjointSet** cu maximum **n** noduri.
  
-  * ''​(f<​sub>​in</sub> + |di|) – f<​sub>​out</​sub>​ = 0''​ , dacă ''​di < 0''​ +</spoiler\\
-  * ''​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. 
  
-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. +===== [Studiu de caz] Prim =====
  
-Exemplu:+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.
  
-{{ :​pa:​laboratoare:​106.png?​250 |}} +==== Prim Pseudocod ====
-  +
-se va transforma in: +
-  +
-{{ :​pa:​laboratoare:​107.png?​250 |}}+
  
-==== Rețea cu limite inferioare de capacitate ====+<spoiler Prim - Pseudocod>​
  
-Există cazuri în care aș vrea ca datele de pe muchiile rețelei sa facă parte dintr-un anumit interval ​''[infsup]''​Pe o astfel de muchie fluxul trebuie să respecte inegalitatea ''​inf ≤ f ≤ sup''​+<code cpp> 
 +// apply Prim's algorithm for computing a Minimum Spanning Tree (MST). 
 +// 
 +// source ​   = source / starting node for computing / expading MST 
 +//             (if not specifiednode 1 is defaulted) 
 +// nodes     = list of all nodes from G 
 +// adj[node= the adjacency list of node 
 +//             ​example:​ adj[node] = {..., (neigh, weight) ...} => edge (node, neigh, weight) 
 +// 
 +// returns: cost, mst 
 +//          cost = the cost of the MST 
 +//          mst = the actual set of edges in MST 
 +// 
 +Prim(source=1,​ G=(nodes, adj)) { 
 +  // STEP 0: initialize results 
 +  // d[node] = distance from MST (any node in current/​partial MST) to node 
 +  // 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 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ă.+  // STEP 0: initialize results 
 +  cost = 0; // cost of the built MST 
 +  mst = {}; // the actual set of edges (u, v) in the built MST
  
-Iată un exemplu de transformare:+  // STEP 1initialize a priority queue 
 +  pq = {};
  
-{{ :pa:​laboratoare:​108.png?​250 |}} +  // STEP 2add the source(s) into pq 
-  +  d[source] = 0;                              // distance from source to MST 
-Bineînțeles că toate aceste transformări pot fi combinate pentru a se ajunge la rețeaua de flux clasică.+  ​p[source] = null;                           // source never has parent 
 +  pq.push( (source, d[source]) );
  
-===== Concluzii și observații =====+  // STEP 3: Build MST. 
 +  while ( !pq.empty() ) { 
 +    // STEP 3.1: Pop next possible node to connect with MST. 
 +    node, _ pq.pop() 
 +    if (used[node]) { 
 +      continue; 
 +    }
  
-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âlniteIn [1și [2gă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)''​.+    // STEP 3.2: Extend MST with edge p[node- node 
 +    used[node= true; 
 +    if (p[node] != null
 +      cost += d[node]; 
 +      mst += { (node, p[node]}; 
 +    }
  
-===== Referinte =====+    // 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
  
-[1Introducere ​in algoritmi, Thomas H. Cormen, Charles E. Leiserson, Ronald R. Rivest – Capitolul VI Algoritmi pe grafuri: Flux maxim+        pq.push( (neigh, d[neigh]) );                   // replace distance for neigh in pq 
 +      } 
 +    } 
 +  }
  
-[2] Introducere in analiza algoritmilorCristian A. Giumale – Cap. V Algoritmi pr grafuri: +  return costmst; 
-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]]+// Usage example: 
 +cost, mst = Prim(1, G=(nodes, edges)); ​// e.gsource = 1, can be any node in G 
 +// 1Use cost of MST. 
 +// 2Use edges of MST (e.g. actually build the tree). 
 +</​code>​ 
 +</​spoiler>​ \\
  
-[4] Resurse wiki – 
-[[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] +==== Complexitate ====
-[[http://​www.cs.princeton.edu/​~wayne/​cs423/​lectures/​max-flow-applications-4up.pdf | Aplicatii flux maxim]]+
  
 +  * **complexitate temporală**:​ $T = O(m * log n)\ sau\ O(|E| * log |V|)$
 +  * **complexitate spațială** : $S = O(n)$
  
-===== Probleme =====+<spoiler Detalii (analiză + optimizări)>​
  
 +  * **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 Dijkstra, putem să obținem:
 +    * **Prim cu heap binar** - $O(m log n)$.
 +    * **Prim cu heap Fibonacci** - $O(n logn + m)$.
 +
 +</​spoiler>​ \\
 +
 +
 +===== TLDR =====
 +
 +  * 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**.
 +
 +===== Exerciții =====
 +
 +
 +<​note>​
 +
 +Scheletul de laborator se găsește pe pagina [[https://​github.com/​acs-pa/​pa-lab/​tree/​main/​skel/​lab11|pa-lab::​skel/​lab11]].
 +
 +</​note>​
 <note warning> <note warning>
-După rezolvarea problemeitoți studenții trebuie să încarce o arhivă cu sursele rezolvării pe Moodle (click ​[[http://cs.curs.pub.ro/2015/mod/assign/​view.php?​id=5853|aici]]) pentru a li se puncta laboratorul.+ 
 +Î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]]. 
 + 
 +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>​ </​note>​
  
-==== Networking (9 pct) ====+==== Kruskal ​====
  
-Pornind de la un graf orientat conex și două noduri ​''​u'' ​și ''​v''​ ale acestuia se cere să se determine următorele elemente: +Se dă un graf **neorientat** ​și **conex** cu **n** noduri și **m** muchii (cu costuri oarecare pe muchii).
-[6p primul punct rezolvat + 3p al doilea]+
  
-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''​.+Folosiți algoritmul lui **Kruskal** ​pentru a găsi un **MST**.
  
-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+Task-uri:
  
-Graful ​din schelet:+  - Găsiți **costul** MST. 
 +  - 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ă.
  
-{{ :​pa:​laboratoare:​graf_flux.png?​150 |}} 
-==== Generare de graf orientat (3 pct) ==== 
  
-Se dă o listă de ''​N''​ noduri, pentru fiecare cunoscându-se gradul de intrare si de ieșire al acestora. Realizați un program care să construiască un graf **orientat** ''​G''​ cu ''​N''​ noduri, care să satisfaca gradele date. Nu se permite mai mult de o muchie între două noduri.\\ +<note warning>
-Exemplu:+
  
-Nod Grad intrare ​Grad iesire ​+Restricții și precizări:​ 
-  ​| ​ 1  |  ​3  ​+ 
-|  2  ​|  ​1  |  2  ​+  * $ n <= 2 * 10^5 $ 
-|  3  |  3  |  ​ +  * $ m <= 4 * 10^5 $ 
-|  4  |  ​  ​1  ​|+  * $ -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. 
 + 
 + 
 +</​note>​ 
 + 
 +==== BONUS ==== 
 + 
 +La acest laborator, asistentul va alege 1-2 probleme din secțiunea extra. 
 + 
 +==== Extra ==== 
 + 
 +  * [[https://​infoarena.ro/​problema/​desen|infoarena/​desen]] 
 +  * [[https://​infoarena.ro/​problema/​radiatie|infoarena/​radiatie]] 
 +  ​* [[https://​infoarena.ro/​problema/​bile|infoarena/​bile]] 
 +  * [[https://​codeforces.com/​problemsets/​acmsguru/​problem/​99999/​323|codeforces/​aviamachinations]] 
 + 
 +===== Referințe ===== 
 + 
 +[0] Chapters **Minimum Spanning Trees**, “Introduction to Algorithms”,​ Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein. 
 + 
 +[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.1463045684.txt.gz · Last modified: 2016/05/12 12:34 by dumitru.cercel
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