Minimum Opspannende Bomen Algoritmiek Toepassingen • Verbinden van punten met zo min mogelijk bekabeling – Netwerkontwerp • Deelroute in andere algoritmen • … 2 Algoritmiek Probleemstelling • Gegeven: een ongerichte graaf G=(N,A) – Iedere kant representeert potentieel aan te leggen verbinding – Kosten/lengte voor elke kant • Gevraagd: Een verzameling kanten F A van minimale totale kosten/lengte zodat de deelgraaf G’=(N,F) samenhangend is 3 Algoritmiek Minimum Opspannende Bomen • Gegeven: – Ongerichte samenhangende graaf G=(N,A) – Lengte l(a) voor elke kant a in A. • Gevraagd: Een boom T = (N, F), zodat – F A, d.w.z. T is een deelboom van G – Elke knoop in G in T zit – De totale lengte van alle kanten in T zo klein mogelijk is. • T is een (minimum) opspannende deelboom 4 Algoritmiek Voorbeeld 4 e c e 3 c 3 a 3 2 11 5 4 a 3 2 1 1 5 4 d b d 1 b 17 1 f Opspannende boom; Geen minimum opspannende boom 5 4 Algoritmiek f Minimum opspannende boom Inhoud • Een principe om minimum opspannende bomen te laten groeien • Twee greedy algoritmen + tijd en datastructuren: – Het algoritme van Kruskal – Het algoritme van Prim-Jarnik 6 Algoritmiek Greedy aanpak • Begin met een woud zonder kanten T=(N,) • Herhaal tot T een boom is – Kies een kant {v,w}, zodat … – Voeg deze kant aan T toe • Output T 7 • Noem T een goed woud als T er een minimum opspannende boom van G bestaat waar T een deelgraaf van is. • We willen als invariant van Greedy algoritme: – T is een goed woud. • Initieel geldt de invariant. Algoritmiek Goed woud: voorbeelden 4 e 4 e 3 c 5 4 3 2 5 4 a 3 a c 3 2 d 1 b d 1 f e f 5 4 a 1 c 3 1 b 4 3 2 d 1 b 1 8 Algoritmiek f Veilige kanten • Stel T=(N,F) is een goed woud. • Een kant {v,w} is veilig, als T’ =(N,F{v,w}) ook een goed woud is. 4 e 9 5 3 2 a 1 1 f 3 2 {a,b} is veilig d b 5 4 d 1 b 3 a 3 c 4 c e Algoritmiek 1 f Greedy algoritme • Begin met een woud zonder kanten T=(N,) • Herhaal tot T een boom is – Kies een veilige kant {v,w} – Voeg {v,w} toe aan T • Output T Maar: welke kanten zijn er veilig?? 10 Algoritmiek Termen • Deelboom in woud • Een kant verlaat een deelboom, als de kant precies 1 eindpunt in de deelboom heeft. c e 3 5 4 a 3 2 d 1 b Elk van de rode kanten verlaat de deelboom met knopen b en f 11 Algoritmiek 1 f Stelling • Stel T is een goed woud. Stel W is een deelboom uit T. Laat de kant {v,w} deelboom W verlaten, en minimum lengte hebben ten opzichte van alle kanten die W verlaten. Dan is {v,w} veilig. c e 3 5 4 a 3 2 {d,f} is veilig d 1 b 12 1 f Algoritmiek Bewijs (1) • Stel T is een goed woud, W een deelboom van T, en {v,w} kant van minimum lengte die W verlaat (als in stelling). • Er is een minimum opspannende boom T’ van G die T als deelwoud heeft. – Omdat T goed is. • Als {v,w} in T’ zit, dan is {v,w} veilig: klaar. • Stel dat {v,w} niet in T’ zit. 13 Algoritmiek Bewijs (2) • T’+{v,w} heeft een cycle. • Deze cycle bevat zowel knopen in W als knopen niet in W. • Er moet nog een kant zijn die W verlaat op de cycle, zeg a. • T’+{v,w} – a is een opspannende boom van G. • De totale lengte van T’+{v,w} – a is hooguit de totale lengte van T’. – Want l({v,w}) l(a). • Dus {v,w} is veilig. 14 Algoritmiek w v a v w Greedy algoritme • Begin met een woud zonder kanten T=(N,) • Herhaal tot T een boom is – Kies een kant {v,w} die minimum lengte heeft t.o.v. alle kanten die een deelboom van T verlaten – Voeg {v,w} toe aan T • Output T Maar: hoe vind je zo’n kant snel? 15 Algoritmiek Twee methoden: overzicht • Kruskal – Kanten worden in volgorde van stijgende lengte bekeken – Groeit verschillende boompjes in woud • Prim-Jarnik – Groeit 1 boom in woud – Steeds wordt de goedkoopste uitgaande kant genomen – Verschillende implementaties 16 Algoritmiek Kruskal: algoritme Sorteer de kanten op niet-dalende lengte, zeg k(1), … , k(a). Begin met een woud zonder kanten T=(N,). for i = 1 to a do if kant k(i) verbindt twee verschillende boompjes in T then voeg kant k(i) toe aan T. (else: we doen niets met deze kant.) Output T. 17 Algoritmiek Kruskal: voorbeeld 4 e c 3 5 4 a 3 2 d 1 b 1 18 Algoritmiek f Kruskal: voorbeeld 4 e c 3 5 4 a 3 2 d 1 b 1 19 Algoritmiek f Kruskal: correctheid • Invariant: T is een goed woud • Blijft behouden omdat toegevoegde kant veilig is (minimum lengte en verlaat deelboom van T) – Mogelijk heeft deze deelboom 1 knoop 20 Algoritmiek Kruskal: implementatie • Belangrijkste problemen: – Bijhouden deelbomen – Testen of kant tussen twee verschillende deelbomen is • Disjuncte verzamelingen datastructuur (union-find) • Voor elke deelboom van T hebben we een verzameling, die de knopen in de deelboom bevat. • Initieel: create(v) voor elke knoop v. • Testen of kant {v,w} tussen twee verschillende boompjes: – Kijk of Find(v) Find(w) • Bij toevoegen van kant {v,w}: Union (Find(v), Find(w) ). 21 Algoritmiek Kruskal: analyse • Sorteren van de kanten kost O(a log a) = O(a log n). • Acties op disjuncte verzamelingen datastructuur: – O(n) creates – O(a) find operaties – O(n) union operaties – O(n+a log* n) tijd totaal (eigenlijk: O(a a(n)).) • Totaal O(a log n) tijd. • Sneller wanneer we de kanten al gesorteerd hebben. • Kan wat versneld worden in praktijk door te stoppen zodra T n – 1 kanten heeft. 22 Algoritmiek Prim-Jarnik: algoritme Kies een knoop s. B = {s}; T=(N, ) veilig while (B N) do vind kant e = {v,w} die B verlaat met minimum lengte (v B, w N – B) T = T { e}; B = B { w }; Output T. 23 Algoritmiek Prim-Jarnik: voorbeeld 4 e c 3 5 4 a 3 2 d 1 b 1 24 Algoritmiek f Prim-Jarnik: voorbeeld 4 e c 3 5 4 a 3 2 d 1 b 1 25 Algoritmiek f Prim-Jarnik: correctheid • Invariant: T is een goed woud • Blijft behouden omdat toegevoegde kant veilig is (minimum lengte en verlaat B, een deelboom van T) 26 Algoritmiek Prim-Jarnik: Implementatie • Houd voor elke knoop v in N – B bij – De kortste kant van een knoop in B naar v: kantnaarb[v] – De lengte van deze kant: dichtbij[v] 27 Algoritmiek Prim-Jarnik: Implementatie Kies een knoop s. B = {s}; T = (B, ); for all v do dichtbij[v] = maxint; kantnaarb[v] = ongedef; for all {s,v} A do dichtbij[v] = l({s,v}); kantnaarb[v] = {s,v}; while (B N) (of: doe n – 1 keer) do Vind v N - B met kleinste waarde van dichtbij[v] T = T {kantnaarb[v]}; B = B {v}; for all {v,w} A met w N - B do if (l({v,w}) < dichtbij[w] ) then dichtbij[w] = l({v,w}); kantnaarb[w] = {v,w}; Output T. 28 Algoritmiek Prim-Jarnik: voorbeeld 4 e c dichtbij kantnaarb 3 5 4 a 3 2 d 1 b 1 29 a maxint ongedef b 1 {b,f} c ongedef d 1 {d,f} e ongedef f f Algoritmiek maxint maxint Prim-Jarnik: voorbeeld 4 e c dichtbij kantnaarb 3 a 2 5 4 a 3 2 1 b 1 30 b c d f Algoritmiek {a,b} maxint ongedef d 1 {d,f} e maxint ongedef f maxint ongedef Prim-Jarnik: voorbeeld 4 e c dichtbij kantnaarb 3 a 2 5 4 a 3 2 b 31 5 {c,d} maxint ongedef d 1 1 b c d {a,b} e f f Algoritmiek Prim-Jarnik: voorbeeld 4 e c dichtbij kantnaarb 3 a 5 4 a 3 2 c d b 32 4 {a,c} 3 {a,e} d 1 1 b e f f Algoritmiek Prim-Jarnik: voorbeeld 4 e c dichtbij kantnaarb 3 a 5 4 a 3 2 c d d 1 b 1 33 b e f f Algoritmiek 4 {a,c} Prim-Jarnik: voorbeeld 4 e c dichtbij kantnaarb 3 a 5 4 a 3 2 c d d 1 b 1 34 b e f f Algoritmiek Prim-Jarnik: Analyse • Belangrijkste probleem: hoe vinden we de kant met de kleinste waarde van dichtbij? • Gebruik priority queue. – Operaties: extract-min, update • O(n) iteraties • O(n) keer een extract min operatie. • O(a) keer een update van een waarde. • Met een gebalanceerde boom: O(a log n) tijd. • Met Fibonacci of hollow heap: O(a + n log n) tijd • Vergelijk met Kruskal: met heap is tijd vergelijkbaar op dichte grafen; met queue implementatie sneller op ijle 35 Algoritmiek grafen, maar langzamer op dichte grafen. Kruskal vs. Prim-Jarnik • Kruskal – Kanten in volgorde van stijgende lengte – Groeit verschillende boompjes in woud – O(a log n + a a(n) ) • Prim-Jarnik – Groeit 1 boom in woud – Steeds wordt de goedkoopste uitgaande kant genomen – O(a + n log n) 36 Algoritmiek