Föreläsning 1: Dekomposition, giriga algoritmer och dynamisk programmering

Relevanta dokument
Föreläsning 12. Söndra och härska

Föreläsning 11 Datastrukturer (DAT037)

Giriga algoritmer och dynamisk programmering

Föreläsning 5: Grafer Del 1

Föreläsning 12. Söndra och härska

Översikt. Stegvis förfining. Stegvis förfining. Dekomposition. Algoritmer. Metod för att skapa ett program från ett analyserat problem

Föreläsning 9 Innehåll. Söndra och härska. Fibonaccitalen. Söndra och härska. Divide and conquer teknik för att konstruera rekursiva algoritmer.

Introduktion till algoritmer - Lektion 4 Matematikgymnasiet, Läsåret Lektion 4

Föreläsning 5: Giriga algoritmer. Kruskals och Prims algoritmer

Magnus Nielsen, IDA, Linköpings universitet

Föreläsning 9 Innehåll. Söndra och härska. Fibonaccitalen. Söndra och härska. Divide and conquer teknik för att konstruera rekursiva algoritmer.

Föreläsning 5: Giriga algoritmer. Kruskals och Prims algoritmer

Föreläsning 5 Innehåll

Tommy Färnqvist, IDA, Linköpings universitet

Tommy Färnqvist, IDA, Linköpings universitet

Föreläsning 4: Kombinatorisk sökning

Föreläsning 5 Innehåll. Val av algoritm och datastruktur. Analys av algoritmer. Tidsåtgång och problemets storlek

Föreläsning 13. Dynamisk programmering

Algoritmer, datastrukturer och komplexitet

Föreläsning 8 Innehåll

Algoritmer, datastrukturer och komplexitet

Föreläsning 5: Dynamisk programmering

Föreläsning 6 Innehåll. Rekursion. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursiv problemlösning. Rekursion. Rekursivt tänkande:

TDDI16 Datastrukturer och algoritmer. Algoritmanalys

Grundläggande datalogi - Övning 3

Föreläsning 7: Syntaxanalys

Algoritmanalys. Inledning. Informationsteknologi Malin Källén, Tom Smedsaas 1 september 2016

Föreläsning 1. Introduktion. Vad är en algoritm?

Algoritmer och effektivitet. Föreläsning 5 Innehåll. Analys av algoritmer. Analys av algoritmer Tidskomplexitet. Algoritmer och effektivitet

Tentamen i Algoritmer & Datastrukturer i Java

Programmering för språkteknologer II, HT2014. Rum

Föreläsning 13. Dynamisk programmering

Datastrukturer, algoritmer och programkonstruktion (DVA104, VT 2015) Föreläsning 6

Exempel: Förel Rekursion III Nr 14. Uno Holmer, Chalmers,

Föreläsning 7 Innehåll. Rekursion. Rekursiv problemlösning. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursion. Rekursivt tänkande:

Algoritmer, datastrukturer och komplexitet

Föreläsning 11. Giriga algoritmer

Föreläsning 10 Innehåll. Prioritetsköer och heapar. ADT Prioritetskö. Interface för Prioritetskö. Exempel på vad du ska kunna

Algoritmer, datastrukturer och komplexitet

Tentamen Datastrukturer D DAT 036/INN960

Lösningsförslag för tentamen i Datastrukturer (DAT037) från

Tentamen Datastrukturer D DAT 036/INN960

Tommy Färnqvist, IDA, Linköpings universitet

Tommy Färnqvist, IDA, Linköpings universitet. 2 Rekursion i C Implementation av rekursion Svansrekursion En till övning...

Föreläsning 11. Giriga algoritmer

public static void mystery(int n) { if (n > 0){ mystery(n-1); System.out.print(n * 4); mystery(n-1); } }

Problemlösning och algoritmer

Föreläsning Datastrukturer (DAT037)

Problemlösning och funktioner Grundkurs i programmering med Python

Lösningsförslag till tentamen Datastrukturer, DAT037,

ADT Prioritetskö. Föreläsning 13 Innehåll. Prioritetskö vs FIFO-kö. Prioritetskö Exempel på användning. Prioritetsköer och heapar

Algoritmer och datastrukturer H I HÅKAN S T R Ö M B E R G N I C K L A S B R A N D E F E L T

String [] argv. Dagens Agenda. Mer om arrayer. Mer om arrayer forts. String [] argv. argv är variabelnamnet. Arrayer och Strängar fortsättning

Föreläsning 4: Giriga algoritmer. Giriga algoritmer

Föreläsning Datastrukturer (DAT036)

Tentamen: Programutveckling ht 2015

Dekomposition och dynamisk programmering

Fredag 10 juni 2016 kl 8 12

FÖRELÄSNING 2, TDDC74, VT2018 BEGREPP PROBLEMLÖSNING MED HJÄLP AV FALLANALYS PROBLEMLÖSNING MED HJÄLP AV REKURSION

Föreläsning 8 Datastrukturer (DAT037)

Bakgrund och motivation. Definition av algoritmer Beskrivningssätt Algoritmanalys. Algoritmer. Lars Larsson VT Lars Larsson Algoritmer 1

Sökning i ordnad lista. Sökning och sortering. Sökning med vaktpost i oordnad lista

Föreläsning 11: Beräkningsgeometri

Programkonstruktion och Datastrukturer

Rekursion. Rekursiv lösningsstrategi. Algoritmkonstruktion. Exempelproblem Hitta största elementet i en sekvens v i där i 1... n.

Innehåll. Föreläsning 12. Binärt sökträd. Binära sökträd. Flervägs sökträd. Balanserade binära sökträd. Sökträd Sökning. Sökning och Sökträd

Föreläsning 9: Talteori

Datastrukturer och algoritmer. Föreläsning 15 Inför tentamen

Föreläsningsanteckningar F6

Exempeltenta GruDat 2002/2003

Datastrukturer och algoritmer

Föreläsning Datastrukturer (DAT037)

Algoritmer, datastrukturer och komplexitet

Föreläsning 1. Introduktion och sökning i graf. Vad är en algoritm?

Föreläsning 4: Kombinatorisk sökning

Föreläsning 13 Innehåll

Föreläsning 2 Datastrukturer (DAT037)

Planering Programmering grundkurs HI1024 HT 2014

Föreläsning ALGORITMER: SÖKNING, REGISTRERING, SORTERING

Föreläsning Datastrukturer (DAT036)

Föreläsning 3-4 Innehåll. Diskutera. Metod. Programexempel med metod

Föreläsning 13 Innehåll

Tentamen TEN1 HI

Introduktion till programmering SMD180. Föreläsning 9: Tupler

Sökning och sortering

Tentamen'('Datastrukturer,'algoritmer'och'programkonstruktion.'

6 Rekursion. 6.1 Rekursionens fyra principer. 6.2 Några vanliga användningsområden för rekursion. Problem löses genom:

Sökning och sortering

Seminarium 13 Innehåll

Föreläsning 12+13: Approximationsalgoritmer

Datastrukturer och algoritmer

Föreläsning 3-4 Innehåll

Sökning och sortering. Sökning och sortering - definitioner. Sökning i oordnad lista. Sökning med vaktpost i oordnad lista

Lektion 2: Sökagenter. Robin Keskisärkkä

Föreläsning 8 Datastrukturer (DAT037)

Föreläsning Datastrukturer (DAT037)

ADT Prioritetskö. Föreläsning 12 Innehåll. Prioritetskö. Interface för Prioritetskö. Prioritetsköer och heapar

Algoritmer och datastrukturer TDA Fredrik Johansson

Transkript:

2D1458, Problemlösning och programmering under press Föreläsning 1: Dekomposition, giriga algoritmer och dynamisk programmering Datum: 2007-09-04 Skribent(er): Anders Malm-Nilsson och Niklas Nummelin Föreläsare: Mikael Goldmann Denna föreläsning tog upp tre av de grundläggande metoderna för att konstruera och klassifiera algoritmer. Dessa metoder benäms som dekomposition, giriga algoritmer samt dynamisk programmering. 1 Dekomposition Dekomposition, eller Söndra och Härska (från engelskans Divide and Conquer ) är en metod som går ut på att dela upp ett större problem i mindre problem. Detta upprepas till dess att alla delproblem har nått en lämplig komplexitetsgrad. Då alla delproblem är lösta kan resultaten från dessa kombineras till det slutgiltiga svaret på problemet. Dock förutsätter detta att delproblemen är av sådan karkatär att deras optimala lösning kan kombineras till en optimal lösning för hela problemet. 1.1 Exempel 1: Skyline Givet n hus som projicerats på ett plan, skall deras skyline beräknas. Med skyline menas den övre kontur som kan fås ur projektionen. Varje hus representeras av en position x, bredd b och höjd h. Utdata är en skyline representerad av m tupler. Varje tupel är en position x och höjd h. Vi börjar med att visa den pragmatiska metoden för att kunna komma fram till en bättre lösning. Den går ut på att kontrollera alla de punkter som varje hus spänner upp på tallinjen och spara undan det hitills högsta värdet hos varje punkt. Efter att detta har utförts för alla hus kan den beräknade höjdbuffern gås igenom från början för att generera en lista med utdata. Tidskomplexiteten för detta blir alltså (n max b max +n max +b max ) eller O(n max b max ). Den slutgiltiga datamängden kommer att vara sorterad efter position. 1

2 2D1458 Popup HT 2006 Algoritm 1: Pragmatisk lösning till Skylineproblemet. Input: U = [x i, b i, h i ] n i=1, n 5000; x, b, h 10000; där n, x, b, h N Output: A = [x i, h i ] m i=1 SLPragmatisk(U) (1) H[0..20000] {0..0}; (2) foreach (x i, b i, h i ) U (3) for i = x i to x i + b i (4) if H i < h i (5) H i h i (6) LH 0 (7) A (8) foreach h i H (9) if h i LH (10) A A (i, h i ) (11) LH h i (12) if LH 0 (13) A A (19999, 0) Då ut-datamängden skall bli sorterad av algoritmen kan man utnyttja sortering hos Mergesort för att skapa en lösning. Sorteringsalgoritmen Mergesort går i O(n log(n)). Den dekompositionerade Skylinealgoritmen är en vidareutveckling av Mergesort och går därför lika fort.

Dekomposition, giriga algoritmer och dynamisk programmering 3 Algoritm 2: Algoritm 2 - Mergefunktionen. Input: U 1, U 2 = [x i, h i ] n i=1, n 5000; x, h 10000; där n, x, h Z Output: A = [x i, h i ] m i=1 SLDekompMerge(U) (1) A = (2) xposition 0 (3) h1 0 (4) h2 0 (5) while U 1 and U 2 (6) (x1 i, h1 i ) U 1.F ront (7) (x2 i, h2 i ) U 2.F ront (8) if x1 i < x2 i (9) xposition x1 i (10) h1 h1 i (11) if h1 < h2 (12) A A (xposition, h1) (13) else (14) A A (xposition, h2) (15) U 1 U 1 \ {(x1 i, h1 i )} (16) else (17) xposition x2 i (18) h2 h2 i (19) if h1 < h2 (20) A A (xposition, h1) (21) else (22) A A (xposition, h2) (23) U 2 U 2 \ {(x2 i, h2 i )} (24) if x1 i = x2 i (25) U 1 U 1 \ {(x1 i, h1 i )}

4 2D1458 Popup HT 2006 Algoritm 3: Lösning till Skylineproblemet, med dekomposition. Input: U = [x i, b i, h i ] n i=1, n 5000; x, b, h 10000; där n, x, b, h Z Output: A[x i, h i ] m i=1 SLDekomp(U) (1) if U = 1 (2) (x, b, h) U.F ront (3) A (4) A A (x, h) (5) A A (x + b, 0) (6) return A (7) return SLDekompMerge(SLDekomp(U[0.. U /2]), SLDekomp(U[ U /2+ 1].. U )) 2 Giriga algoritmer Med giriga algoritmer menas sådana problemlösningsalgoritmer som vid varje val tar det beslut som ger mest utdelning. Då denna typ av algoritm alltid strävar efter den lokalt bästa lösningen innebär det att den lösningen inte alltid blir globalt optimal. Vi kommer dock att använda giriga algoritmer för att lösa problem där vi kan visa att den giriga algoritmen faktiskt ger en optimal lösning. 2.1 Exempel 2: Intervalltäckning Givet en mängd intervall mellan heltalspunkterna L och R på en tallinje, finn det minsta antalet intervall som behövs för att täcka alla heltalspunkter mellan L och R.

Dekomposition, giriga algoritmer och dynamisk programmering 5 Algoritm 4: Girig algoritm för intervalltäckning. Input: U = [a i, b i ] n i=1, L, R; i A[a i, b i ] [L, R] Z Output: A {x i, h i } IntervallTäckning(U) (1) A (2) while L < R (3) longest 0; (4) f oundinterval f alse (5) foreach (a i, b i ) U (6) if (a i L and b i L) (7) if b longest < b i (8) longest i (9) f oundinterval true (10) break (11) if foundinterval = false (12) return (13) A A {longest} (14) L b longest + 1 Tidskomplexiteten för algoritmen blir alltså O(n 2 ), då en linjärsökning sker för varje interval. Genom att sortera listan kan sökningen göras snabbare då sökintervallet hela tiden kommer att förminskas. Man kan även utföra sökningen med hjälp av binärsökning, vilket resulterar i tidskomplexiteten O(n log(n)). 2.2 Exempel 3: Pianoflyttarna P stycken pianoflyttare har tagit på sig att flytta m pianon under n dagar (dag 1 är en måndag ). Tyngden gör att två flyttare endast kan flytta ett piano per dag. Varje piano kan dessutom bara flyttas mellan två datum, a och b. Är det möjligt för dem att flytta alla pianon? Är det dessutom möjligt för dem att vara lediga på helgerna?

6 2D1458 Popup HT 2006 Algoritm 5: Girig algoritm för pianoflyttarna. Input: U = [a i, b i ] m i=1, P, n; 1 a; b 100; P, m, n, a, b Z Output: boolean Pianoflytt(U) (1) for i = 0 to n (2) if (i mod 7 = 6) or (i mod 7 = 0) (3) continue (4) finnsp P 2 (5) dag i (6) while finnsp > 0 (7) foreach (a j, b j ) U (8) if a j > dag (9) continue (10) if b j < dag (11) return false (12) if b j = dag (13) if finnsp = 0 (14) if dag = i then return false (15) else break (16) else (17) U U \ {(a j, b j )} (18) if U = (19) return true (20) finnsp finnsp 1 (21) dag dag + 1 (22) if dag = n (23) return true (24) if dag > i (25) i dag 1 Pianoflyttarna arbetar på det sättet att de alltid tar de mest kritiska jobben, d.v.s. de flyttar de pianon som är närmast sitt slutdatum. Först flyttas de pianon som måste flyttas idag, sen de som måste flyttas imorgon och så vidare tills dess att det inte finns några pianoflyttare kvar idag. Genom att man alltid tar de mest kritiska jobben först så får man garanterat en optimal lösning. Tidskomplexiteten för detta blir O(n 2 ). Om listan med pianoflyttningsjobb sorteras efter slutdatum kan analysen istället göras i linjär tid. Tidskomplexiteten blir då O(n log(n)). 3 Dynamisk programmering Dynamisk programmering är en metod som går ut på att ta till vara resultatet från tidigare lösta delproblem, så att dessa inte behöver lösas igen. Vi skall nu studera ett problem som enkelt kan tidsoptimeras med hjälp av dynamisk programmering.

Dekomposition, giriga algoritmer och dynamisk programmering 7 3.1 Exempel 4: Binomialtermen Vi vill beräkna binomialtermen. Med matematisk notation kan den rekursiva algoritmen beskrivas som: { ( n ) 1 ) om k = 0 eller k = n = k + ( ) n 1 k annars ( n 1 k 1 Pseudokoden för den rekursiva algoritmen blir då: Algoritm 6: Rekursiv algoritm för att finna ( n) k. Input: n, k Z där n k 0 Output: ( n) k Binom(n, k) (1) if k = 0 or k = n (2) return 1 (3) else (4) return Binom(n 1, k 1) + Binom(n 1, k) Denna kräver alltså O (( )) n k operationer, då alla basfall, d.v.s. alla 1:or, är de som skall summeras till resultatet. Det är ( ) n k = n! k!(n k)! operationer. Det värsta fallet är alltså k = floor( n 2 ) då k n och k 0, d.v.s. O( n! (floor( n 2 )!) (ceil( n 2 )!)). Med hjälp av dynamisk programmering kan detta problem optimeras till O (nk) operationer. Man utnyttjar att det, då rekursionsträdet expanderas, finns flera överlappande grenar, vilka därför bara behöver expanderas och beräknas en gång. Denna teknik brukar vanligtvis kallas för dynamisk programmering och kan göras på två olika sätt, med sina för och nackdelar: Algoritm 7: Algoritm för att finna ( n) k, top-down med memoisering. Input: n, k Z där n k 0 Output: ( n) k Binom(n, k) (1) if k = 0 or k = n (2) return 1 (3) else if computed[n, k] true (4) computed[n, k] = true (5) tab[n, k] = Binom(n 1, k 1) + Binom(n 1, k) (6) return tab[n,k] Top-down -metoden fungerar så att värden beräknas och sparas undan i en tabell först när de efterfrågas och inte redan har beräknats. Metoden att spara undan resultatet från funktionsanrop för återanvändning brukar vanligtvis kallas memoisering (från engelskans memoization ). Detta är bra om man har en stor spridning på indata och inte vet vilka tal som kommer att behöva beräknas.

8 2D1458 Popup HT 2006 Algoritm 8: Algoritm för att finna ( n) k, bottom-up. Input: n, k Z där n k 0 Output: ( n) k Binom(n, k) (1) for i = 0 to n (2) tab[i, 0] = tab[i, i] = 1 (3) for i = 2 to n (4) for j = 1 to min(i-1, k) (5) tab[i, j] = tab[i 1, j 1] + tab[i 1, j] (6) return tab[n, k] Med Bottom-up -metoden förberäknar man istället hela tabellen. Detta är bra då man är intresserad av att få ut många eller alla av de värden som blir beräknade i tabellen. Ibland kan det även vara en bra metod att använda om många eller alla värden i tabellen behövs för att nå resultatet. Observera att tabellen bara behövs beräknas en gång. Sedan kan värdena hämtas i konstant tid. 3.2 Exempel 5: Kretskortskonstruktion Två chip med n ben är konstruerade så att varje chip har alla sina ben liggandes mot det andra chipets ben. Benen på båda kretsarna är numrerade men tillverkaren av den ena kretsen lyckades inte lägga benen i ordning. Tillverkaren som nu skall använda kretsarna kan inte dra ledningarna mellan benen i kors utan måste lägga korsande ledningar som olika lager. Vi ska undersöka hur man kan gå tillväga för att hitta det största antalet kopplingar som kan finnas i ett lager (längsta växande delsekvens). Två algoritmer skall nu visas som båda använder sig utav kretsuppsättningen nedan. y x 1 1 2 3 3 6 4 4 5 2 6 5 Man kan skapa en växande delsekvens med hjälp av en girig algoritm, där man tar de kopplingar som fungerar om man börjar uppifrån i listan och går neråt. Denna algoritm finner endast en växande delsekvens. Det man kan konstatera är att om man finner den längsta växande delsekvensen har man funnit det maximala antalet kopplingar som kan finnas i lagret. Om y styr kopplingarna ger den giriga algoritmen kopplingar mellan (1, 2, 5) medan x ger (1, 3, 6). Då man undersöker tabellen finner man att den längsta växande delsekvensen för denna krets är (1, 3, 4, 5), så ingen av lösningarna gav den längsta delsekvensen. Den giriga algoritmen gav alltså ingen optimal lösning.

Dekomposition, giriga algoritmer och dynamisk programmering 9 För att kunna finna den längsta växnade delsekvensen utan att behöva göra en totalsökning, så använder vi oss utav dynamisk programmering. Man använder sig utav en vektor last[] där last[i] är det lägsta värdet som kan avsluta en delsekvens som är i lång. last[0] initieras till medan resterande poster i last initieras till. För varje x[i] måste man nu finna det första j så att last[j 1] < x[i] last[j]. De värden som last[] är initierad till gör att, för varje x[], en sådan alltid kommer att finnas. När denna är funnen sätter man last[j] = x[i]. Tabellen nedan visar hur algoritmen fungerar. Algoritmen lägger antingen elementet efter det sista non- elementet i listan eller byter ut ett element i listan. I kolumnerna för 1, 3 och 6 byter algoritmen ut värden då värdet x[i] är större än raden ovanför men <. 6:an får sedan byta plats med 4:an då 3 < 4 < 6 och i nästa kolumn får 2:an gå in i stället för 3:an då 1 < 2 < 3. I sista kolumen läggs sedan in en 5:a i slutet. Om binärsökning används för att finna det element som skall skrivas last-vektorn blir algoritmens tidskomplexitet O(n log(n)). start 1 3 6 4 2 5 last[0] last[1] 1 1 1 1 1 1 last[2] 3 3 3 2 2 last[3] 6 4 4 4 last[4] 5 last[5] last[6] Tabellen ger oss nu antalet element i den maximalt växande delsekvensen. Detta ges av att räkna antalet element i sista kolumnen som inte är eller -. Genom att använda denna tabell kan även man ta fram den längsta växande delsekvensen, vilket inte visas här.