Divide-and-Conquer Lars Vidar Magnusson 13.1.2015 Kapittel 4 Maximum sub-array problemet Matrix multiplikasjon Analyse av divide-and-conquer algoritmer ved hjelp av substitusjonsmetoden
Divide-and-Conquer Algoritmer Divide (Del/Split) problemet opp i et antall delproblemer som er mindre instanser av samme problem. Conquer (Beseir/Hersk) delproblemene ved å løse dem rekursivt. Når delproblemen er små nok kan de løses enkelt. Combine (Kombiner) løsningene for delproblemene til en løsning for det orginale problemet.
Divide-and-Conquer Algoritmer Recursive Case Når delproblemene er store nok til å måtte deles opp ytterligere Base Case Når delproblemene er blitt små nok stopper rekursjonen opp (bottoms out)
Recurrences Recurrences (gjentagelser) er ligninger som beskriver en funksjon ved hjelp av seg selv på mindre input. Recurrences går hånd i hånd med divide-and-conquer algoritmer. Under er recurrence-ligningen for Merge-Sort som vi har hevdet er Θ(n log n). { Θ(1) if n = 1 T (n) = 2T (n/2) + Θ(n) if n > 1 Vi skal se på tre metoder for å løse recurrences i.e. finne asymptotiske grenser for løsningen.
Maximum-Subarray Problemet Å finne maksimum subarray (delarray) av en array med positive og negative tall kalles maximum-subarray problemet. Kan benyttes for å finne beste tidspunkt for å kjøpe og selge aksjer i aksjehandel. Kan løses brute-force ved å teste alle ( n 2) mulige varianter, men vi skal se om ikke vi kan finne en mer effektiv algoritme ved hjelp av divide-and-conquer.
Find-Maximum-Subarray Å finne maksimum-subarray i en array kan deles i to ved å dele input i to, slik vi gjorde med Merge-Sort. Vi får da en av tre muligheter Maksimum subarray ligger i venstre halvdel Maksimum subarray ligger i høyre halvdel Maksimum subarray ligger mellom de to delene Vi kan sjekke de to første enkelt ved hjelp av rekursjon, men den siste trenger en egen hjelpefunksjon.
Find-Max-Crossing-Subarray Find-Max-Crossing-Subarray(A, low, mid, high) 1 left-sum = 2 sum = 0 3 for i = mid downto low 4 sum = sum + A[i] 5 if sum > left-sum 6 left-sum = sum 7 max-left = i 8 right-sum = 9 sum = 0 10 for j = mid + 1 to high 11 sum = sum + A[j] 12 if sum > right-sum 13 right-sum = sum 14 max-right = j 15 return (max-left, max-right, left-sum + right-sum)
Analyse av Find-Max-Crossing-Subarray Vi kan enkelt finne de asymptotiske grensene for Find-Max-Crossing-Subarray ved å telle løkker. Vi har to løkker som begge itererer gjennom en andel av hele input. Siden løkkene kommer etter hverandre og ingen av de avbrytes under spesielle vilkår så er Find-Max-Crossing-Subarray = Θ(n).
Find-Maximum-Subarray Find-Maximum-Subarray(A, low, high) 1 if high == low 2 return (low, high, A[low]) 3 else mid = (low + high)/2 4 (left-low, left-high, left-sum) = Find-Maximum-Subarray(A, low, mid) 5 (right-low, right-high, right-sum) = Find-Maximum-Subarray(A, mid + 1, high) 6 (cross-low, cross-high, cross-sum) = Find-Max-Crossing-Subarray(A, low, mid, high) 7 if left-sum right-sum and left-sum cross-sum 8 return (left-low, left-high, left-sum) 9 elseif right-sum left-sum and right-sum cross-sum 10 return (right-low, right-high, right-sum) 11 else return (cross-low, cross-high, cross-sum)
Analyse av Find-Maximum-Subarray Når vi skal analysere Find-Maximum-Subarray holder det ikke å telle løkker. Vi må i stedet benytte oss av recurrences til å finne de asymptotiske grensene.
Analyse av Find-Maximum-Subarray I basis tilfellet, når n = 1, vil bare de første linjene av algoritmen kjøres i.e. T (1) = Θ(1). De to rekursive kallene tar begge halvparten av orginalinput i.e 2T (n/2). Kallet til Find-Max-Crossing-Subarray vil som vi fant tidligere kjøre på Θ(n) tid. Vi ender da opp med følgende recurrence-ligning. { Θ(1) if n = 1 T (n) = 2T (n/2) + Θ(n) if n > 1 Dette er den samme ligningen som vi fikk for Merge-Sort i.e. Find-Maximum-Subarray = Θ(n log n).
Matrix Multiplikasjon Matrix multiplikasjon mellom to 2 2 matriser A og B. [ ] [ ] a11 a A = 12 b11 b B = 12 C = AB a 21 a 22 b 21 b 22 Vi kan finne koeffisientene i matrisen C kan finnes ved å løse følgende ligning c ij = a i1 b 1j + a i2 b 2j Generelt for n n matriser kan vi finne c ij med følgende ligning. n c ij = a ik b kj k=1 Siden det er n 2 koeffisienter i en n n matrise ender vi da opp med at Square-Matrix-Multiply = Θ(n 3 ).
Square-Matrix-Multiply-Recursive For å gjøre oppgaven litt enklere så sier vi at vi bare jobber med n n matriser hvor n {2 x : x N}. En multplikasjon av to n n matriser kan da gjøres ved å dele en matrise opp i 4 stykk n/2 n/2 delmatriser. A = ( ) A11 A 12 A 21 A 22 B = ( ) B11 B 12 B 21 B 22 C = ( ) C11 C 12 C 21 C 22 Delmatrisene settes så sammen igjen etter multiplikasjonen. ( ) ( ) ( ) C11 C C = 12 A11 A = 12 B11 B 12 C 21 C 22 A 21 A 22 B 21 B 22
Square-Matrix-Multiply-Recursive Square-Matrix-Multiply-Recursive(A, B) 1 n = A.rows 2 let C be a new n n matrix 3 if n == 1 4 c 11 = a 11 b 11 5 else partition A, B, and C 6 C 11 = Square-Matrix-Multiply-Recursive(A 11, B 11 ) +Square-Matrix-Multiply-Recursive(A 12, B 21 ) 7 C 12 = Square-Matrix-Multiply-Recursive(A 11, B 12 ) +Square-Matrix-Multiply-Recursive(A 12, B 22 ) 8 C 21 = Square-Matrix-Multiply-Recursive(A 21, B 11 ) +Square-Matrix-Multiply-Recursive(A 22, B 21 ) 9 C 22 = Square-Matrix-Multiply-Recursive(A 21, B 12 ) +Square-Matrix-Multiply-Recursive(A 22, B 22 ) 10 return C
Analyse av Square-Matrix-Multiply-Recursive Vi har i basis-tilfellet n = 1 en kjøretid T (1) = Θ(1). I det rekursive tilfellet deles hver av de to n n matrisene opp i fire n/2 n/2 matriser og vi gjør 8 rekursive kall i.e. 8T (n/2). Vi må legge sammen resultatene fra de rekursive kallene, hver med n 2 /4 elementer i.e. hver av de fire addisjonene krever Θ(n 2 ) tid. Algoritmen har utelatt et viktig element, delingen av matrisene. Dette kan gjøres i enten konstant tid (Θ(1)) ved hjelp av indekser, eller i kvadratisk tid (Θ(n 2 )) ved hjelp av kopiering.
Analyse av Square-Matrix-Multiply-Recursive Utifra hva vi kom frem til på forrige slide så får vi følgende recurrence-ligning. { Θ(1) if n = 1 T (n) = 8T (n/2) + Θ(n 2 ) if n > 1 Som vi snart skal se gir dette en total kjøretid er Θ(n 3 ) som ikke er bedre enn direkte multiplikasjon. Legg merke til at vi kan fjerne konstante ledd i asymptotiske leddene men ikke i leddene som refererer til seg selv (T (n)) i recurrence-ligningen.
Strassen s Matrix Multiplikasjon Kjøretiden til den rekursive algoritmen for matrisemultiplikasjon kan forbedres fra Θ(n 3 ) til Θ(n log 7 ). Dette gjøres ved å redusere antallet nødvendige rekursive kall fra 8 til 7 ved å dele opp matrisen på en annen måte. Dette kalles Strassen s metode for matrisemultiplikasjon og er nøye dokumentert i boka.
Løse Recurrences med Substitusjonsmetoden Substitusjonsmetoden er den mest primitive av de tre metodene vi dekker i kurset, og kan derfor også oppfattes som den vanskeligste. Den kan beskrives med to enkle steg 1 Gjett på formen til løsningen e.g. Θ(n log n) 2 Bruk matematisk induksjon til å finne konstanter og vise at løsningen virker. Vi kan bruke substitusjonsmetoden til å finne både øvre og nedre grenser. En kraftig metode, men er svært avhengig av analytikers evne til å gjøre gode gjetninger.
Eksempel på Substitusjonsmetoden La oss bruke substitusjonsmetoden for å finne en øvre grense for T (n) = 2T (n/2) + n. Vi gjetter på at denne gjentagelsen er O(n log n). Da må vi bevise at T (n) cn log n for en eller annen positiv konstant c. T (n) 2(c( n/2 ) log( n/2 )) + n cn log(n/2) + n = cn log n cn log 2 + n = cn log n cn + n cn log n Dette holder for c 1.
Eksempel på Substitusjonsmetoden Det andre kravet i matematisk induksjon er at grensetilfellen må være oppfylt. Dette kan noen ganger bli et problem. Et eksempel er basistilfellet T (1) = 1. T (1) > 1 log 1 = 0 Dette oppfyller ikke kravet om at T (n) cn log n, men definisjonene av de asymptotiske grensene tillater at vi prøver oss med større verdier for n 0. La oss prøve n 0 = 2 i stedet. Vi setter først inn i likningen. T (2) = 2T (1) + 2 = 4 Dette oppfyller kravet, siden T (2) cn log n = 2c er gyldig for c 2.
Vanskeligheter med Substitusjonsmetoden Mye av vanskelighetene med substitusjonsmetoden går ut på å gjette riktig. Erfaring hjelper Begynn med løse grenser og jobb innover Siden vi jobber med matematisk induksjon kan vi ikke lenger være slappe med konstanter og lavere-ordens ledd. Alt må være formelt.