Grådige Algoritmer Lars Vidar Magnusson 12.3.2014 Kapittel 16 Grådige algoritmer Aktivitetvelgingsproblemet Huffmankoder
Ideen bak Grådige Algoritmer Ideen bak grådige algoritmer er å løse optimaliseringsproblem ved å gjøre valg som ser best ut akkurat nå. Vi gjør lokalt optimale valg Håper på en global optimal løsning Grådige algoritmer gir ofte en effektiv løsning. Gir ikke alltid global optimal løsning. Sammenlignes i boka med dynamisk programmering.
Aktivitetvelgingsproblemet Vi skal illustrere hvordan en grådig algoritme fungerer ved å se på en konkret optimaliseringsproblem. Vi har et sett S med aktiviteter S = {a 1, a 2,..., a n } som krever eksklusiv tilgang til en felles ressurs. Hver aktivitet a i har en starttid s i og en avslutningstid f i, hvor 0 s i < f i <. To aktiviteter a i og a j er kompatible hvis de to intervallene [s i, f i ) og [s j, f j ) ikke overlapper hverandre. I aktivitetvelgingsproblemet ønsker vi å finne største subsett av S med kompatible aktiviteter.
Løse Aktivitetvelgingsproblemet For å løse aktivitetvelgingsproblemet så begynner vi med å anta at aktivitetene er sortert etter når de avsluttes i.e. f 1 f 2 f n. Vi kan si at aktivitetvelgingsproblemet har en såkalt optimal substruktur (optimal substructure). En optimal løsning A som inneholder en aktivitet a i består av a i pluss den optimale løsningen(e) for delmengden(e) av S {a i }. Vi kan finne global optimal løsning ved å utføre grådige valg av aktivitet
Eksempelaktiviteter Tabellen under inneholder et sett S med eksempelaktiviteter som vi kommer til å bruke for å illustrere hvordan en grådig algoritme som løser aktivitetvelgingsproblemet fungerer. i 1 2 3 4 5 6 7 8 9 10 11 s i 1 3 0 5 3 5 6 8 8 2 12 f i 4 5 6 7 9 9 10 11 12 14 16 Aktivitetene er sortert i monotonisk stigende rekkefølge på når de avsluttes. Den optimale løsningen er ikke unik siden både {a 1, a 4, a 8, a 11 } og {a 2, a 4, a 9, a 11 } er kompatible subsett med samme antall aktiviteter.
Optimal Substruktur for Aktivitetvelgingsproblemet Vi vil vise at aktivitetvelgingsproblemet har optimal substruktur. Vi sier at subsettet S ij er aktivitetene som starter etter at a i er ferdig og er ferdig før a j starter. Aktiviteter i S ij er kompatible med S ij = {a k S : f i s k < f k s j } Alle aktiviteter som er ferdig innen f i Alle aktiviteter som ikke starter før s j
Optimal Substruktur for Aktivitetvelgingsproblemet Vi lar settet A ij være det subsettet med flest kompatible aktiviteter i S ij og a k A ij. Da har vi to delproblem Finn kompatible aktiviteter i S ik Finn kompatible aktiviteter i S kj A ik = A ij S ik er aktivitetene i A ij som er ferdig før a k starter. A kj = A ij S kj er aktivitetene i A ij som starter etter at a k er ferdig. Da har vi at A ij = A ik {a k } A kj, som impliserer at A ij = A ik + A kj + 1. Dette er en påstand om at en optimal løsning A ij må inneholde de optimale løsningene for delproblemene for S ik og S kj. Se boka for et enkelt bevis.
En Mulig Rekursiv Løsning Siden den optimale løsningen A ij må inneholde de optimale løsningene for delproblemene S ik og S kj kan den skrives som en recurrencelikning. Vi lar c[i, j] være størrelsen til den optimale løsningen for S ij. Da har vi c[i, j] = c[i, k] + c[k, j] + 1, men det gjenstår å velge a k. { 0 if Sij = c[i, j] = max ak S ij {c[i, k] + c[k, j] + 1} if S ij Vi kan utvikle en rekursiv løsning for dette, men uten noen triks ville det blitt en svært så ineffektiv algoritme. Dynamisk programmering kan benyttes til å effektivt løse slike problem. Bottom-Up Alternativt bruke memoizing Grådige algoritmer kan også i noen tilfeller benyttes til å løse slike problem, og i disse tilfellene vil det ofte lede til svært så effektive algoritmer. Top-Down
Grådig Strategi Problemet med en normal rekursiv algoritme ligger i at det blir ineffektivt å finne løsningen på delproblemene for enhver k på hvert nivå i rekursjonstreet før man kan velge beste k. Den grådige strategien går ut på å grådig velge den k som ser best ut før man løser delproblemene. I tilfellet for aktivitetvelgingsproblemet vil et grådig valg kunne være å velge den aktiviteten i S ij som gir rom for flest mulig andre aktiviteter. Vi velger aktiviteten som er ferdig først. Siden aktivitetene er sortert i stigende rekkefølge på når de avsluttes, vil dette ganske enkelt bare være å velge a 1 (første element i S ij ). Da gjenstår det bare å finne optimale løsning på aktivitetene som avsluttes etter at a 1 er ferdig.
Mer om den Grådige Strategien Vi har nå redusert problemet slik at vi på hvert nivå bare får ett delproblem. Vi kan derfor endre litt på notasjonen vår S k refererer til alle aktiviteter etter a k er ferdig (etter s k ) S k = {a i S : s i f k } Utifra at problemet har optimal substruktur så vet vi hvis a 1 er med i en optimal løsning så inneholder den totale optimale løsningen a 1 plus løsningen på alle aktivitetene i S 1. Da gjenstår det bare å vise at den optimale løsningen inneholder a 1.
Siste Rest om den Grådige Strategien Teorem Hvis S k ikke er tom og a m er aktiviteten som er tidligst ferdig i S k så er a m med i en optimal løsning. Proof. Vi lar A k være en optimal løsningen for S k og a j er den aktiviteten i A k som er tidligst ferdig. Hvis a m = a j så er vi ferdige. Hvis ikke kunne vi ha byttet ut a j med a m i A k uten at det ville ført til konflikter eller minket antallet aktiviteter i A k. Vi kan derfor i aktivitetvelgingsproblemet finne optimale løsninger ved å bruke en grådig strategi. Vi kan finne en optimal løsning ved å bygge den fra toppen og ned (Vi trenger ikke bruke dynamisk programmering)
Rec-Actictivity-Selector Algoritmen Utifra diskusjonen om aktivitetvelgingsproblemet sålangt kan vi enkelt lage en rekursiv algoritmen som løser problemet. Rec-Actictivity-Selector algoritmen er listet under. s er starttidene til aktivitetene, f er avslutningstidene, k er gjeldende delproblem og n er antall aktiviteter totalt. Første kall er Rec-Actictivity-Selector(s, f, 0, n), hvor f 0 = 0 og S 0 = S.
Hvordan Rec-Actictivity-Selector Fungerer
Analyse av Rec-Actictivity-Selector Algoritmen Når vi analyserer tidsbruken til Rec-Actictivity-Selector algoritmen må vi ta høyde for at vi har antatt at aktivitetene er sorterte på når de avsluttes. Det tar Θ(n log n) tid å sortere n aktiviteter. Rec-Actictivity-Selector algoritmen besøker hver aktivitet en gang i.e. aloritmen har kjøretid på Θ(n). Totalt får algoritmen derfor kjøretid på Θ(n log n).
En Iterativ Utgave Greedy-Actictivity-Selector algoritmen listet under er en iterativ utgave av Rec-Actictivity-Selector. Greedy-Actictivity-Selector algoritmen har samme kjøretid som Rec-Actictivity-Selector i.e. Θ(n) eller Θ(n log n) hvis aktivitetene må sorteres.
Grådig Strategi Å utvikle en grådig algoritme for et optimaliseringsproblem kan sammenfattes med følgende steg. 1 Gjør om optimaliseringsproblemet til et problem hvor man kan gjøre et valg og stå igjen med bare et delproblem å løse. 2 Bevis at det grådige valget leder til en optimal løsning ved å vise at en optimal løsning som tar det grådige valget eksiterer. 3 Demonstrer at problemet har optimal substruktur ved å vise at kan få en optimal løsning ved å sette sammen resultatet for delproblemet med det grådige valget. Det finnes ingen generell måte å bedømme om et problem kan løses med en grådig strategi eller ikke, men det er to nøkkelkomponenter Gradig valg egenskapen Optimal substruktur
Grådig Valg Egenskapen Med grådig valg egenskapen (greedy choice property) menes at vi viser at det grådige valget leder til en optimal løsning. Se på en optimal løsning. Hvis den inneholder det grådige valge så er vi ferdig med beviset. Hvis ikke, modifiser den optimale løsningen slik at den inneholder det grådige valget, og vis at den like god som den orginale optimale løsningen. Vi kan utvikle raske algoritmer ved å utnytte den grådige egenskapen. Proprosesser input i grådig rekkefølge. Eller, hvis dynamisk data, bruk en prioritetskø.
Optimal Substruktur Med optimal substruktur så menes at en optimal løsning kan finnes ved å sette sammen et grådig valg og den optimale løsningen for delproblemet. Det er ikke alltid et problem har en slik struktur Fractional Knapsack problemet har optimal substruktur 0-1 Knapsack problemet har ikke en slik struktur Vi har en sekk med plass til 50 vektenheter, og vi har følgende tre objekter. v i angir verdien, w i angir vekten og v i /w i er verdi per vektenhet. i 1 2 3 v i 60 100 120 w i 10 20 30 v i /w i 6 5 4
Huffmankoder Huffmankoder er en enkel komprimeringsmetode som kan spare mellom 20% og 80% avhengig av input. Et enkelt eksempel på data som kan komprimeres kan være en sekvens av karakterer. Algoritmen bruker en tabell som gir frekvensen til hver karakter til å utføre grådige valg. Det finnes mange måter å representere huffmankoder, men vi skal se på binære karakterkoder (binary character codes eller bare codes). Vi gir hver karakter et kodeord (codeword) Hvis vi bruker et fast antall bits (fixed-length code) til hver karakter vil vi f.eks. bruke 3 bits for å lagre 6 karakterer. Med et variabelt antall bits (variable-length code) per karakter kan vi få vesentlig bedre komprimering ved å gi karakterer med høy frekvens korte kodeord.
Et Eksempel på Input og Koder Tabellen under viser et eksempel med 6 karakterer. Vi har en sekvens med 100000 tegn/karakterer Med fixed-length koder trenger vi 3 100000 = 300000 bits Med variable-length koder trenger vi (45 1 + 13 3 + 12 3 + 16 3 + 9 4 + 5 4) 1000 = 224000 bits
Prefix Koder Et eksempel på hvordan man lage variable-length koder er å bruke prefiks koder (prefix codes) hvor ingen kodeord er en prefiks av et annet. Figuren til venstre viser et tre for fixed-length koder Figuren til høyre vise et tre for prefix koder
Huffman Algoritmen Huffman algoritmen er en algoritme for å bygge et tre som angir prefiks kodene for tegnene. Vi begynner med alle tegnene C i barnenodene sammen med frekvensen til tegnet. Vi bruker en prioritetskø Q sortert på frekvensen til en node. Vi utførere et antall merges for å bygge treet fra bunnen og opp.
Huffman Pseudokode Huffman algoritmen er listet i pseudokode under. Huffman(C) 1 n = C 2 Q = C 3 for i = 1 to n 1 4 allocate a new node z 5 z.left = x = Extract-Min(Q) 6 z.right = y = Extract-Min(Q) 7 z.freq = x.freq + y.freq 8 Insert(Q, z) 9 return Extract-Min(Q)
Hvordan Huffman Algoritmen Fungerer Figuren under viser hvordan Huffman algoritmen fungerer.