F11 Läsanvisning: kap 10 + dessa OH Kruskals algoritm kortaste vägar en till alla Dijkstras algoritm (Den här föreläsningen är också delvis samma som en från algoritmkursen därav språkvalet.) För lab 3: observera att boken inte tar upp Kruskal och att det är en av versionerna från OH bilderna ni skall implementera i labben se OH 18. Det är också OH bildernas version av Dijkstra ni skall använda på labben, se OH 17. Nästa gång pratar vi om sortering: quicksort och mergesort Grafer 3 1
Minimum Spanning Tree property Let G = (V, E) be a connected graph with positive edge costs, assume all are distinct. Let S be any subset of nodes from G = (V, E) that is neither empty nor equal to V, and let edge e = (u, v) be the minimum-cost edge with one end in S and the other in V-S, Then every MST contains the edge e. Thanks to the MST property it's easy to find minimum spanning trees. Grafer 3 2
Kruskals algorithm - idéa Idéa: grow a set of connected components (cc) choose the cheapest edge that does not create a cycle We start with a tree without edges where every node is a connected component. In every step we choose the cheapest edge that connects two nodes in different connected components (to avoid cycles) When every node is in the same cc wher'e done. Grafer 3 3
Kruskal based on the Mst-property: first pseudocode While there are edges left { Find cheapest edge Add to the mst if it does not create a cycle } - How to prove that it works? (assume for now :-), see algorithms course) Minor :-) implementation details are left to deal with: - How to keep track of cycles? use MFsets - How to enumerate all edges? - How to find cheapest edge? - How to add to the MST? - What is the complexity? Grafer 3 4
second pseudocode version adding more detail: using Mfsets Cc = Connected components with each node in separate component while nbr Of Cc > 1 loop (u,v) = get cheapest edge from edges if u and v are in different Cc then add (u, v) to the MST merge the Cc of u and v nbrofcc-- end if end while ToDo list: - How to implement Cc? last lecture - How to find cheapest edge? use p-queue - How to enumerate all edges? - How to add to the MST? use a list - What is the complexity? need more detail Grafer 3 5
Refined version two : Pseudocode kruskal(g: graph(v, E)) return set of edges 0 MFset cc // a Merge-Find set Set mst = nodes u, v int nbrofcc = n //the growing spanning tree 1 insert all edges in a priority queue 2 while nbrofcc > 1 loop 3 (u,v) = deletemin(edges) 4 ucomp = find(u, cc), vcomp = find(v, cc) 5 if ucomp vcomp then 6 merge(ucomp, vcomp, cc) 7 nbrofcc = nbrofcc - 1 8 add (u, v) to mst end if end while return mst end kruskal If find O(logn), merge O(1), deletemin O(logn) then altogether this is: O(eloge) = O(elogn) since n-1 <= e <= n 2. Grafer 3 6
Complexity it is likely that n<e and that e<n 2 (n-1<=e<=n 2 ) MFset/UFset: assume tree implementation => - union/merge O(1) - find O(logn) (if the tree is balanced) Deletemin: put all edges in a priority queue (impl. with a heap). - deletemin, insert/add O(loge) row what cost why 0 init n for init. of cc, 1 insert in pq eloge + 2 while e each edge only once 3 deletemin (loge + see above 4 2*find 2loge + logn<=loge if n<e 5 if 1 + comparing numbers 6 merge 1 + se above 7 decrease 1 + trivially 8 insert/add 1) a list n + eloge + e(loge+2loge+4) O(eloge) this is also O(elogn) because e<n 2 Grafer 3 7
Some steps to developing an usable algorithm: Define the problem. - Find an (any) algorithm to solve it. - Prove it works. - Analyse the algorithm Fast enough? ( enough is relative) If not, figure out why, - Look at the complexity analysis. - Better datastructures? - Optimizations in the algorithm? - Completely new algorithm? i.e find a way to address the problem. Iterate until satisfied. Grafer 3 8
Dijkstra - Kortaste vägen en till alla Hur hittar vi kortaste vägen från en startnod, tex nod 1, till alla de andra noderna? Ännu en gammal algoritm från 1959 som är väldigt lik Prims algoritm dvs den bygger på precis samma idé. Vi har en riktad graf med positiva kostnader. -antag att nod 1 är startnod - starta med alla direktvägar från nod 1 dvs ssf(i) = cost(1,i) i (ssf=shortest so far) - välj billigaste bågen (antag det är till 5) - undersök om man kan gå billigare från nod 1 till de övriga om man går via nod 5 dvs ssf(5) + cost(5, x) < ssf(x) x ssf(x) = min [ssf(x), ssf(5) + cost(5, x)] x (ssf = shortest so far) Grafer 3 9
Dijkstras är väldigt lik bokens första impl. av Prims algoritm (jag gick inte igenom den). Som i Prim använder vi oss av två mängder. S (kallad known här) innehåller alla noder för vilka vi beräknat kortaste vägen och V-S alla de andra. Vi har också två vektorer d och p där d(v) ( kallas här ssf(v), shortest so far ) innehåller nuvarande kortaste vägen från s till v och p(v) innehåller föregångaren till v i vägen från s till v. p har samma innehåll som i Prims algoritm men d innehåller nu kostnaden för hela vägen till v. I Prim var det bara kostnaden för sista bågen. Och naturligtvis ser uppdateringen av d (ssf) och p lite annorlunda ut i Dijkstra. Grafer 3 10
pseudocode - Dijkstra pseudocode dijkstra(g: graph (V,E)) ssf : array(1..n) of shortest paths so far v, w, u: nodes known = {1} // the start node while known V loop choose the edge (u, w) with minimum cost s.t. u known and w V-known add (w) to known +remove from V-known for all v on EL(w) loop end loop end dijkstra if it is shorter to go by way of w update ssf(v) and p(v) (note ssf = d in the book) röd text är skillnaden mot Prim + att ssf innehåller hela vägen Grafer 3 11
jobba lite med pseudokoden pseudocode dijkstra(g : graf) return ssf and p 1 known = {1}; // known == S in book 2 for all v in V-known // initialize 3 p(v) = 1 4 ssf(v) = cost(1,v); // ssf==d in book end loop; 5 while V-known not empty 6 find the smallest ssf(w) w in V-known 7 add w to known 8 remove w from V-known 9 for all v in EL(w) and in V-known // compare cost by way of w 10 ssf(v) = min[ ssf(v), ssf(w) + cost(w,v) ] 11 set p(v) to w if ssf(w)+cost(w,v) < ssf(v) end loop end loop end dijkstra p(i) = startnod tex 1, p(v) = w om ssf ändras p(k) = noden omedelbart före k i kortaste vägen Grafer 3 12
p(i) = startnod tex 1, p(v) = w om ssf ändras p(k) = noden omedelbart före k i kortaste vägen Grafer 3 13
antag E-matris komplexitet Dijkstra Handviftning: rad 6 och loopen på rad 9 tar O(n). De exekveras n gånger av rad 5 => O(n 2 ) Noggrannare analys: rad vad kostnad varför 1 init HT n+ init av V-known 2 for all n*( en nod per varv 3 1+ tilld. i fält 4 1)+ oavsett EM eller EL 5 while n*( en nod varje varv 6 find n+ rak sökning 7,8 add/rem. 1+ 9 for all v n*( (matris!) 10 ssf(v)= 5+ aritm op.+ uppslag 11 set 1) ) n+n*(1+1) + n*(n+1+ n*(5+1) ) = n+2n+n 2 +n+6n 2 = 1+3n+8n 2 O(n 2 ) Kan vi göra något åt find? Och rad 9? Grafer 3 14
komplexitet Dijkstra antag E-lista e<<n 2 så pröva en E-lista istället och en prioritetskö rad vad kostnad varför 1-4 O(n)+ init 5-6 nlogn totalt över alla varv (tag ut noderna och återställ kön, max n noder) 9-10 elogn totalt över alla varv (gå igenom EL för w, om inte v finns där så är cost(w,v) =, om v finns så uppdaterar vi den specialdesignade p-kön (se tavlan). Det finns totalt e bågar och vi går igenom E-listorna så detta kan ta max elogn Totalt: nlogn + n + nlogn + elogn skapa p-kö + 1-4 + 4-5 + 7-8 O((n+e)logn) Grafer 3 15
printpath (v: nod; p: vektor) if v = startnod then put(startnod) else printpath(p(v), p) put (, ) put(v) end if end printpath p(v) innehåller noden omedelbart före v i kortaste vägen dvs p(2) = 4 innebär att nod 4 kommer före nod 2 på vägen från startnoden nod 1 2 3 4 5 p = {1, 4, 1, 3, 1} dvs kortaste vägen 1->2 är printpath(2), 2 printpath(4), 4 printpath(3), 3 printpath(1) 1 Grafer 3 16
Lab 3: Variant av Dijkstra Följande variant av Dijkstra som ger kortaste vägen från en startnod till en slutnod skall ni implementera på lab 3. Här sparar vi innehållet i vektorerna d och p i p-kön. Ett köelement skall innehålla (to, cost, path): - noden man kommit till, - kostnaden för vägen dit från startnoden och - vägen dit från startnoden lägg (startnod, 0, tom väg) i en p-kö while p-kön inte är tom (nod, cost, path) = första elementet i p-kön if nod ej är besökt if nod är slutpunkt returnera path else markera nod besökt for every v on EL(nod) if v ej är besökt lägg in nytt köelement för v i p-kön Grafer 3 17
Lab3: Kruskal med try 2: a list ala F10 oh 11 - en förenklad Kruskal 0 skapa ett fält cc som för varje nod innehåller en egen tom lista (som skall innehålla bågar så småningom) (dvs varje nod är i en egen komponent) 1 Lägg in alla bågar i en prioritetskö 2 Så länge pq, ej är tom && cc > 1 3 hämta e = (from, to, weight) från kön 5 om from och to inte refererar till samma lista i cc 6 flytta över alla elementen från den kortare listan till den andra och se till att alla berörda noder i cc refererar till den påfyllda listan 8 lägg slutligen e i den påfyllda listan resultatet dvs det sökta MST finns i den enda kvarvarande listan i cc. (denna variant skall implementeras på labben) Grafer 3 18
Grafen: Torrsimning Start: p-queue 1-3 4-6 2-5 3-6 1-4 3-4 2-3 3-5 5-6 1-2 Grafer 3 19
1 2 { 1-3 } { } 3 4 5 6 { } { } { } 1 2 { 1-3 } { 2-5 } 3 4 { 4-6 } 5 6 Grafer 3 20
3-6 läggs in 1 och 4 pekar på samma lista 3 och 4 pekar på samma lista 2 3 läggs in klart, observera att kön inte är tom ännu Grafer 3 21
komplexitet förenklade Kruskal rad vad kostnad varför 0 skapa fält n + max n noder 1 p-kö eloge + max e bågar 2 while e e bågar i p-kön 3 uttag (loge + deletemin på heap 5 if!samma 1 + jmf pekare 6 flytta n/2 + längden av korta listan 8 1) trivialt n + eloge +e (loge + 1 + n/2 + 1) = n + eloge + eloge + e + en/2 + e = n + 2e + 2eloge + en/2 O(en) Kan tyvärr jämföras med O(n 2 ) eftersom n<e Det är rad 6 (merge) som är problemet Grafer 3 22