Divide & Conquer: Verdeel en Heers Algoritmiek
Algoritmische technieken Trucs; methoden; paradigma’s voor het ontwerp van algoritmen Gezien: Dynamisch Programmeren Hierna: Greedy Vandaag: Divide & Conquer Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Los probleem op in 3 stappen: Divide: splits in deelproblemen Conquer: los deelproblemen recursief op Combine: voeg deeloplossingen samen tot oplossing hele probleem (Vgl. dynamisch programmeren: topkeuze verschillende deelproblemen) Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Divide et impera Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer MergeSort Sorteert deel van array X inclusief ondergrens a, exclusief bovengrens b MergeSort[int[] X, int a, int b] MergeSort[X, a, (a+b)/2] MergeSort[X, (a+b)/2, b] Merge[X, a, (a+b)/2, b] NB: soms laat ik basisgeval weg Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer MergeSort Combineren Basisgeval Opl. geheel Opl. deelproblemen Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer MergeSort Divide: hak lijst doormidden Conquer: sorteer helften Combine: voeg gesorteerde lijsten samen tot 1 gesorteerde lijst Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Maximum Maximum[int[] X, int a, int b] if(a + 1 == b) return X[a]; L = Maximum[X, a, (a+b)/2] R = Maximum[X, (a+b)/2, b] return max[L, R] Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Optellen Divide and Conquer Iteratief Sum[int[] X, a, b] if(a + 1 == b) return X[a] s1 := Sum[X, a, (a+b)/2] s2 := Sum[X, (a+b)/2, b] return s1 + s2 Verschillen? Sum[int[] X, a, b] accum := 0 for(i:=a; i<b; i++) accum += X[i] return accum Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Optellen Divide and Conquer Iteratief Sum[int[] X, a, b] if(a + 1 == b) return X[a] s1 := Sum[X, a, (a+b)/2] s2 := Sum[X, (a+b)/2, b] return s1 + s2 Minder afrondfouten Parallelisme (concurrency) Sum[int[] X, a, b] accum := 0 for(i:=a; i<b; i++) accum += X[i] return accum Minder overhead Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Nog een voorbeeld Voorwaarts verschil: 1x kopen, 1x verkopen Week 1 2 3 4 5 6 Prijs 9 7 Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Voorwaarts Verschil Splits het array in twee stukken: links en rechts Drie gevallen: Inkoop en verkoop zitten allebei links Inkoop en verkoop zitten allebei rechts Inkoop zit links en verkoop zit rechts Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Voorwaarts Verschil Voorwaarts Verschil is maximum van: V.V. links V.V. rechts Max rechts – Min links Week 1 2 3 4 5 6 Prijs 9 7 v.v = 5 min = 2 v.v = 2 max = 5 Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Drie gevallen Inkoop en verkoop zitten allebei links Recursief op linkerkant Inkoop en verkoop zitten allebei rechts Recursief op rechterkant Inkoop zit links en verkoop zit rechts … Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Drie gevallen Inkoop en verkoop zitten allebei links Recursief op linkerkant Inkoop en verkoop zitten allebei rechts Recursief op rechterkant Inkoop zit links en verkoop zit rechts Koop links zo goedkoop mogelijk (minimum) Verkoop rechts zo duur mogelijk (maximum) Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Voorwaarts Verschil Methode die als return-waarde een drietal getallen oplevert: (min, max, maxverschil) Method MaxVerschil[int[] X, a, b] (minL, maxL, vl) = MaxVerschil[a,(a+b)/2]; (minR, maxR, vr) =MaxVerschil[(a+b)/2, b]; antw = max { vl, vr, maxR-minL }; Return (min{minL,minR}, max{minR,maxR}, antw) Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Voorwaarts Verschil Divide: hak lijst doormidden Conquer: bereken v.v. helften Combine: max van vv’s, max right – min left Algoritmiek: Divide & Conquer
Hoeveel tijd? … en verder … O(n), want: T(n) = 2 T(n/2) + O(1) Of “accounting” Kan het sneller: W(n) Maar misschien wel wat betreft de constante factor Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Andere strategieën Simplificatie … Divide in n-1 en 1 Kijk naar de eerste twee elementen… Slimme scan Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Vermenigvuldigen Twee getallen van 𝑛 cijfers Motivatie: cryptografie, numerieke wiskunde Soms getal te groot voor 32/64-bits Basisschool-methode: Θ 𝑛 2 1234__ 2753 x 2702__ 6170___ 8638____ 2468 x 3397202__ Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Vermenigvuldigen Twee getallen 𝐴,𝐵 van 𝑛 cijfers Splits: 𝐴= 𝐴 1 ⋅ 10 𝑛/2 + 𝐴 2 𝐵= 𝐵 1 ⋅ 10 𝑛/2 + 𝐵 2 Deelproblemen? Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Vermenigvuldigen Multiply[A, B] M := 10^(n/2) A1 := A / M ; A2 := A % M B1 := B / M ; B2 := B % M X1 := Multiply(A1, B1) X2 := Multiply(A1, B2) X3 := Multiply(A2, B1) X4 := Multiply(A2, B2) RETURN X1*M*M + X2*M + X3*M + X4 Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Hoeveelheid werk Stel een recurrente betrekking op 𝑇 𝑛 =4𝑇 𝑛/2 +𝑂(𝑛) Vier vermenigvuldigingen van half zo lange getallen Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Kan het sneller? 𝐴 1 𝐵 1 𝑀 2 +𝑀⋅ 𝐴 1 𝐵 2 + 𝐴 2 𝐵 1 + 𝐴 2 𝐵 2 𝐴 1 + 𝐴 2 ⋅ 𝐵 1 + 𝐵 2 = 𝐴 1 𝐵 2 + 𝐴 2 𝐵 1 + 𝐴 1 𝐵 1 + 𝐴 2 𝐵 2 Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Kan het sneller? 𝐴 1 𝐵 1 𝑀 2 +𝑀⋅ 𝐴 1 𝐵 2 + 𝐴 2 𝐵 1 + 𝐴 2 𝐵 2 𝐴 1 + 𝐴 2 ⋅ 𝐵 1 + 𝐵 2 = 𝐴 1 𝐵 2 + 𝐴 2 𝐵 1 + 𝐴 1 𝐵 1 + 𝐴 2 𝐵 2 Ruil 2 verm. voor 1 verm. + 3 optel. Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Vermenigvuldigen Multiply[A, B] M := 10^(n/2) A1 := A / M ; A2 := A % M B1 := B / M ; B2 := B % M X1 := Multiply(A1, B1) X2 := Multiply(A2, B2) X3 := Multiply(A1+A2, B1+B2) RETURN X1*M*M + M*(X3-X1-X2) + X2 Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Hoeveelheid werk Nieuwe recurrente betrekking 𝑇 𝑛 =𝟑𝑇 𝑛/2 +𝑂(𝑛) Hoeveel sneller is dit? analyse… Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Master Theorem Zegt iets over: 𝑇 𝑛 =𝑎𝑇 𝑛/𝑏 +𝑓(𝑛) MergeSort: 𝑇 𝑛 =2𝑇 𝑛/2 +𝑂(𝑛) Verm. 1: 𝑇 𝑛 =4𝑇 𝑛/2 +𝑂 𝑛 Verm. 2: 𝑇 𝑛 =3𝑇 𝑛/2 +𝑂 𝑛 Optel: 𝑇 𝑛 =2𝑇 𝑛/2 +𝑂(1) Master Theorem (kort): Neem de b-log van a (log met grondtal b van a, log_b a). Vergelijk n^(log_b a) met f(n). De grootste is de looptijd, tenzij ze op log-factoren na hetzelde zijn. Dan is de looptijd f(n)log n. Zie boek voor details en twee randgevallen. Algoritmiek: Divide & Conquer
Snel vermenigvuldigen 𝑇 𝑛 =𝟑𝑇 𝑛/2 +𝑂(𝑛) 2 getallen vermenigvuldigen in 𝑂( 𝑛 1.585 ) (Dit heet: Karatsuba-vermenigvuldiging) Het kan nog sneller, in 𝑂(𝑛 log 𝑛 log log 𝑛 ), dit is moeilijk. Boek hf. 30. Algoritmiek: Divide & Conquer
Snel Vermenigvuldigen Divide: splits de getallen in 2 helften Conquer: bereken (3/4) producten Combine: optelsom Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Subtitutie MT kan niet alles aan Subtitutie: formuleer vermoeden, bewijs het Op basis ervaring, experiment of vermoeden Soort inductiebewijs Maak impliciete constante expliciet Je krijgt ondergrens op 𝑐 Complexiteit van Merge Sort: SUBSTITUTIE. Voor de verdeelde Merge-sort instanties geldt: M(n) = M(n/2) + M(n/2) + O(n) Verwar een aanroep niet met de tijd van die aanroep! Op toetsen zie ik nog wel eens zoiets als dit verschijnen. FOUT: M(n) = n/2 + n/2 + O(n). Maar in de fase van het OPSTELLEN van de vergelijking mag je nooit zomaar "een aanroep op n/2 waarden" verwarren met "n/2 tijd". Zelfs niet als er later O(n) uit blijkt te komen. Uit Datastructuren weet je waarschijnlijk nog dat alle goeie sorteeralgoritmen O(n.lgn) zijn, dus deze waarschijnlijk ook. Afronding bij instantiegrootte is niet van belang voor O. Moet je iets weten over atomaire instantie (base case)? Nee, impliciet veronderstellen we altijd: M(1) = O(1), namelijk, een base case is altijd begrensd door de tijd van de duurste base case. We noemen dit een recurrente betrekking omdat de waarde van M(n) wordt uitgedrukt in de waarde voor kleinere instanties. Als je al een idee hebt van wat de oplossing van zo'n vergelijking is, dan kun je proberen dat te bewijzen met de SUBSTITUTIE-methode, in feite een soort inductie. Inductie: je leidt iets af "voor n" waarbij je AANNEEMT cq GEBRUIKT dat het geldt voor kleinere waarden. Wat nu hier de belangrijkste stap is: het EXPLICITEREN van de IMPLICIETE constante. Dwz we gaan niet bewijzen "M(n) is O(n.lgn)", maar we gaan bewijzen "M(n) <= c.n.lgn", alleen zonder te noemen wat c is. Waarom is dit EXPLICITEREN nodig? Je wordt anders namelijk genept door GELDIGE afleidingsregels voor O, bv: O(n) + O(n) = O(n) Waarom is dit op zich geldig? Als ik twee expressies heb, de ene in waarde begrensd door c1.n en de tweede door c2.n, dan is de som begrensd door (c1+c2).n, dus inderdaad EEN constante maal n. Alleen het is een andere constante dan waar ik mee begon. FOUTIEF BEWIJS VAN M(n) = O(n): Stel M(n') = O(n') voor alle n'< n, Dan is M(n) = M(n/2) + M(n/2) + O(n) Rec Betr = O(n/2) + O(n/2) + O(n) Gebruik voor n/2 = O(n) Rekenregel O Probleem is dat de impliciete constante in de laatste O NIET dezelfde is als in de eerdere O. Dus ik ga constantes expliciet maken. Er is een constante d waarbij als gegeven geldt M(n) <= M(n/2) + M(n/2) + d.n Wat ik ga bewijzen is M(n) <= c. n lgn Waarbij ik als inductiehypothese gebruik: M(n') <= c. n'.lgn' voor alle n'< n In de afleiding komen vrijwel altijd dezelfde stappen terug: + Gegeven gebruiken, + Ind Hyp gebruiken, + Vereenvoudigen + Kijken waar je naar toe wilt + Een slimme afschatting maken Het bewijs gaat zo: Dan geldt M(n) <= M(n/2) + M(n/2) + d.n Rec Betr <= c. n/2 lg(n/2) + c. n/2 . lg(n/2) + d.n Ind Hyp = c.n.lg (n/2) + d.n Termen combineren = c.n.(lg n - 1) + d.n Eigenschap lg = c.n.lgn - c.n + d.n Distributie Nu kom ik op een stap die niet voor alle c geldt: <= c.n.lgn MITS c >= d Het is niet vreemd dat ik op een restrictie op c kom; ik probeer immers te bewijzen M(n) <= c.n.lgn en dit zal niet voor kleine c waar zijn. Maar als c groot genoeg is (dus >= d) dan is deze inductiestap GELDIG. Je ziet dat ik voor M(n) DEZELFDE c heb afgeleid als ik heb aangenomen voor M(n'). Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Consumentengids Best uit de test & beste koop Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Consumentengids Kwaliteit 78 76 74 72 71 65 47 31 Prijs €1199 €1229 €709 €1553 €801 €632 €459 €599 “Best uit de Test” – gewoon de beste. Wat is “Beste Koop”? Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Consumentengids Kwaliteit 78 76 74 72 71 65 47 31 Prijs €1199 €1229 €709 €1553 €801 €632 €459 €599 “Best uit de Test” – gewoon de beste. Wat is “Beste Koop”? Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Dominatie Een product domineert een ander product als zowel: De prijs lager is En de kwaliteit hoger Wil: lijst van niet-gedomineerde producten (Pareto-front) Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Dominatie Dominatie[product[] X, int a, int b] Sorteer X op kwaliteit Dominatie[X, a, (a+b)/2] Dominatie[X, (a+b)/2, b] …? Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Consumentengids Kwaliteit 78 76 74 72 71 65 47 31 Prijs €1199 €1229 €709 €1553 €801 €632 €459 €599 78 76 74 72 €1199 €1229 €709 €1553 71 65 47 31 €801 €632 €459 €599 Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Consumentengids Kwaliteit 78 76 74 72 71 65 47 31 Prijs €1199 €1229 €709 €1553 €801 €632 €459 €599 78 76 74 72 €1199 €1229 €709 €1553 71 65 47 31 €801 €632 €459 €599 Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Consumentengids Kwaliteit 78 76 74 72 71 65 47 31 Prijs €1199 €1229 €709 €1553 €801 €632 €459 €599 78 76 74 72 €1199 €1229 €709 €1553 71 65 47 31 €801 €632 €459 €599 Rechts domineert nooit links Waneer domineert links rechts? Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Consumentengids Kwaliteit 78 76 74 72 71 65 47 31 Prijs €1199 €1229 €709 €1553 €801 €632 €459 €599 78 76 74 72 €1199 €1229 €709 €1553 71 65 47 31 €801 €632 €459 €599 801>709 Rechts domineert nooit links Waneer domineert links rechts? Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Dominatie Dominatie[product[] X, int a, int b] Sorteer X op kwaliteit Dominatie[X, a, (a+b)/2] Dominatie[X, (a+b)/2, b] p* := minimale prijs [a,(a+b)/2) filter uit [(a+b)/2, b) als p>p* Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Looptijd 𝑇 𝑛 =2𝑇 𝑛/2 +𝑂 𝑛 log 𝑛 Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Looptijd 𝑇 𝑛 =2𝑇 𝑛/2 +𝑂 𝑛 log 𝑛 𝑇 𝑛 =𝑂(𝑛 log 2 𝑛 ) Dom! Je sorteert te vaak… Let bij D&C op: Geen overbodig werk: sorteren, array kopiëren Bereken in recursie hulpwaarden (v.v; opgave WC) Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Dominatie Het kan véél simpeler Kwaliteit 78 76 74 72 71 65 47 31 Prijs €1199 €1229 €709 €1553 €801 €632 €459 €599 𝑚𝑖𝑛=632 D&C is niet altijd de beste oplossing. Hier: loopje over de lijst (gesorteerd op kwaliteit, van links naar rechts), voeg label toe als je een kleinere prijs tegenkomt dan dat je eeder hebt gezien. Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Dominatie Het kan véél simpeler Lineair als lijst voorgesorteerd Kwaliteit 78 76 74 72 71 65 47 31 Prijs €1199 €1229 €709 €1553 €801 €632 €459 €599 𝑚𝑖𝑛=459 D&C is niet altijd de beste oplossing. Hier: loopje over de lijst (gesorteerd op kwaliteit, van links naar rechts), voeg label toe als je een kleinere prijs tegenkomt dan dat je eeder hebt gezien. Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Dominatie Divide & Conquer-algoritme is bouwsteen: Werkcollege: uitbreiding naar 3D Divide & Conquer is vaak één van de mogelijkheden: Mergesort v.s. Heapsort Dominatie Algoritmiek: Divide & Conquer
Algoritmiek: Divide & Conquer Conclusie Divide & Conquer: techniek om algoritmen te ontwerpen Splits probleem, los deelproblemen op, combineer Analyse: Master Theorem, Substitutie Algoritmiek: Divide & Conquer