Choices, choices Tiende forelesning Dynamisk programmering: En serie med valg der valgmulighetene er avhengige av hva vi har valgt før. DAG- SP er erkeeksemplet (og den underliggende modellen for all DP). 1
Ha DAG-SP i bakhodet! Relax inn fra forg jengere, i topologisk sortert rekkefølge. «Oppskrift» på dynamisk programmering. 1. Karakteriser strukturen til en optimal løsning. 2. Definér verdien til en optimal løsning rekursivt. 3. Beregn den optimale verdien «bottom-up», og ta vare på del-løsninger. struktur definisjon 4. Beregn løsningen som ga den optimale verdien. Memoisering (merk: bare én «r»): Kjør rekursjonen direkte, men lagre delløsninger (og bruk dem i stedet for rekursjon, om mulig). beregning løsning 2
Kjent? 3
Erke- Eksempel «DAG-Shortest-Path» 4
Erke- e s k E l e p m Dijkstra blir ganske likt, bare at vi har litt grådighet i tillegg (og at den topologiske ordningen må jukses til litt). forgjengere minimum topsort, relax tilbakesporing Tilbakesporingen g jøres ved at vi setter en forg jenger i en forg jentertabell hver gang vi endrer minimum i dollar-fasen. Standardløsning. «DAG-Shortest-Path» 5
Eksempel Floyd-Warshall 6
Ek s l e p em innom hvem? min(med, uten) innom 1, 2, tilbakesporing Floyd-Warshall 7
Noen nye Går ikke igjennom samlebåndseksemplet her. Viktig, på mange måter, siden det er «typisk DP» men det er egentlig bare DAG-SP, som vi jo har snakket om en del fra før. 8
Eksempel Samlebånd 9
Vi har to samlebånd, med ulike tider på hver stasjon. Vi kan skifte samlebånd, med et visst tidstap. Hva blir det billigste «programmet» (serien med valg)? Valgene må tas «dynamisk» de er avhengige av nåværende tilstand. Kan prøve alle muligheter; 2^n alternativer Dette kan løses med DAG- Shortest-Path, men som tidligere sagt: DP *er* jo egentlig bare DAG-SP, uansett. Det gjelder bare å finne DAGen 10
Frem til S1,j Legg merke til den rekursive sammenhengen. j = 1: Enkelt sjekk tiden til S 1,j j 2: To alternativer Frem til S 1,j 1 og så til S1,j Frem til S 2,j 1 og så til S1,j Vi må finne optimal vei frem til forgjengeren! Optimal løsning baserer seg på optimale del-løsninger. Flere løsninger baserer seg på de samme del-løsningene. En enkel rekursiv implementasjon ville ha hatt eksponensiell kjøretid. 11
fi[j] er laveste tid g jennom til Si,j. f* er laveste tid g jennom hele systemet. =,, =, =,..., li[j] som Vi definerer = hvilken linje vi kom fra (der l* er den siste). = ( +, + ) = +, = +, =,..., = ( +,, +, +, ) = ( +,, +, +, ) = 12,,
Hver f-verdi er bare avhengig av forrige kolonne. Bygg «oppover», fra grunn-tilfellet i rekursjonen (f.v. m.h.). Fyll ut tabellene. l- tabellen er nærmest et «biprodukt». 13
Oppnøsting av løsning: Bruk l-tabellen til å «nøste» deg bakover. Som sagt: Spesialtilfelle av DAG-SP. 14
Hvorfor ikke bruke rekursjon direkte, uten å lagre del-løsninger i en tabell? r1(n) = r2(n) = 1 La ri(j) være antall referanser til fi[j]. r 1(j) = r2(j) = r1(j+1) + r2(j+1), for j = 1 n 1 Induksjon: Anta at r i(j+1) = 2 n (j+1) r i(j) = ri(j+1) + r3 i(j+1) = 2n (j+1) + 2 n (j+1) = 2 n j f 1[1] refereres 2 n 1 ganger 15 Det har blitt påstått at computer scientists bare kan bevise ting med induksjon Men det holder jo for mye rart :-) Hurra for induksjon!
Eksempel 0/1 Ryggsekkproblemet 16
50 10 20 30 $60 $100 $120 17
30 $120 20 $100 30 $120 20 $100 10 $60 10 $60 18
Delproblemparametre: Hvor stor plass har vi (igjen)? Hvor mange objekter har vi (igjen)? På sett og vis litt som Floyd-Warshall: Hvilke objekter får vi bruke? (Men også: Hvor mye plass får vi bruke?) 19
0 c[i, w] = c[i 1, w] max{vi + c[i 1, w wi ], c[i 20 1, w]} if i = 0 or w = 0 if wi > w if i > 0 and w wi
DP-01K(v, w, n, W) for k 0 W c[0, k] 0 for i 1 n c[i, 0] 0 for k 1 W if w[i] k if v[i] + c[i 1, k w[i]] > c[i 1, k] c[i, k] v[i] + c[i 1, k w[i]] else c[i, k] c[i 1, k] else c[i, k] c[i 1, k] 21
Som før: Ta vare på valg i hver rute Nøst deg bakover fra siste rute 22
Pseudopolynomisk kjøretid: Polynomisk avhengig av verdien til et heltall som er en del av instansen altså egentlig eksponentiell som funksjon av problemstørrelsen (målt i lagringsplass). Dette er verdt å ha med seg når vi ser på NP-kompletthet. Problemet er NPkomplett, og ingen kjenner noen polynomiske løsninger på slike problemer så da hadde det jo vært rart om kjøretiden var polynomisk :-) Kjøretid: O(nW) Lett å gå seg bort i disse tingene. Pseudopolynomiske algoritmer kan faktisk være ganske effektive i praksis, f.eks. for rimelige verdier av W i dette tilfellet. Ikke polynomisk pseudopolynomisk! Hvis m = lg W er problemstørrelsen O(n + m) og kjøretiden O(n2 m ) 23
Ek s l e p em Optimale søketrær 24
Optimaliseringskriteriet blir den vektede (med vekt p_i) summen av dybdene (+1) til nøklene k_i. K = [k 1,, kn], k1 < k2 < < kn Vil bygge et binært søketre over K Sannsynlighet p i for søk etter ki Vil minimere forventet søkekostnad Antar at alle søk lykkes. 25
Forventet søketid: 2.15. ( ) ( ) 26
Forventet søketid: 2.10. (Optimalt.) Merk: Ikke sikkert vi vil ha minimal høyde. Heller ikke sikkert den høyeste sannsynligheten ender i rota. ( ) ( ) 27 Brute force: Bygg alle mulige binære søketrær (BST), og sett inn nøklene. Beregn forventet søkekostnad. Velg beste. Men det er Ω(4 n /n 3/2 ) BST-er med n noder.
Hvis T inneholder nøklene ki kj så må T være optimalt for disse nøklene vises lett ved selvmotsigelse. < <> 28
: & Hvis vi antar at rota inneholder kr (som en hypotese) så vil alle k<kr være til venstre (og tilsv. for høyre). Begge deltrær må (som nevnt i forrige foil) være optimale for de gitte nøklene. Hvis vi undersøker alle k = ki kj som mulige røtter, og har (og løser problemet rekursivt) så er vi garantert å finne den optimale løsningen for ki kj! : 6 : &?1 : &+1 : ; 29
But w(8, ; ) = w(8, * 1) + 2* + w(* + 1, ; ). Hvis j = i 1 er treet tomt. Therefore, &[8, ; ] = &[8, * 1] + &[* + 1, ; ] + w(8, ; ). e[i, j] er forventet kostnad for optimalt BST over ki kj. This equation assumes that we already know which key is <*. We don t. Try all candidates, and pick the best one:! 0 if ; = 8 1, &[8, ; ] = min {&[8, * 1] + &[* + 1, ; ] + w(8, ; )} if 8 ;. 8 * ; Could write a recursive algorithm... As usual, we ll store the values in a table: Vi legger til w(i, j) (dvs. alle p-ene legges til én gang) fordi høyden til alle noder i deltrærne øker med én. w(i, j) er summen av pi pj &[ "1.. #$ 6 + 1%, 0.. 6% ] " #$ 30
[trekk pusten dypt] 31
OPTIMAL-BST( 2, >, 6) 8 1 6 + 1 &[8, 8 1] 0 w[8, 8 1] 0? 1 6 8 1 6? + 1 ; 8 +? 1 &[8, ;] w[8, ;] w[8, ; 1] + 2 ; * 8 ; Kubisk kjøretid. return & and *,,( l (liten L) i hovedløkken er størrelsen på deltrærne vi beregner. i er start og j er slutt for nøklene i det aktuelle deltreet. ( &[8, * 1] + &[* + 1, ;] + w[8, ;] ( < &[8, ;] &[8, ;] ( *,,([8, ;] * 32
CONSTRUCT-OPTIMAL-BST(&(($) & &(($[1, 4] print? & is the root CONSTRUCT-OPT-SUBTREE(1, & 1, &, left, &(($) CONSTRUCT-OPT-SUBTREE(& + 1, 4, &, right, &(($) CONSTRUCT-OPT-SUBTREE(6, <, &, @6&, &(($) 6 < $ &(($[6, <] print? $ is @6& child of? & CONSTRUCT-OPT-SUBTREE(6, $ 1, $, left, &(($) CONSTRUCT-OPT-SUBTREE($ + 1, <, $, right, &(($) 33
Eksempel Longest Common Subsequence. Finner en felles subsekvens hos to sekvenser. Lengden kan brukes som et likhetsmål. Denne type algoritmer er vanlig i bioinformatikk og informasjonsg jenfinning. LCS 34
Noen eksempler. En Brute Forceløsning vil ha en kjøretid på Θ(n2^m) ser du hvorfor? s p r i n g t i m e h o r s e b a c k p i o n e e r s n o w f l a k e m a e l s t r o m h e r o i c a l l y b e c a l m Merk: John Stewarteksemplet ser bare på snittet av bokstavmengdene et mye enklere problem (som lett kan løses i lineær tid vha. f.eks. hashing). 35 s c h o l a r l y
X i = [x1,, xi], Yi = [y1,, yi] X = X m, Y = Yn Z = [z 1,, zk] er en LCS av X og Y 36
Hvis de ikke deler siste element kan LCS-en utvides en selvmotsigelse. Hvis x m = yn: z k = xm = yn og Z k 1 er en LCS av Xm 1 og Yn 1 Det samme gjelder her hvis Xm-1 og Yn-1 har en lenger felles subsekvens så kan vi finne en lenger total felles subsekvens enn Z igjen en selvmotsigelse. 37
Hvis xm yn og zk xm: I begge tilfeller må Z være en felles subsekvens. Hvis det eksisterte en som var lenger vil den også være lenger totalt en selvmotsigelse. Z er en LCS av X m 1 og Y Hvis xm yn og zk yn: Z er en LCS av X og Y n 1 38
c[i,j] er lengden på en LCS av Xi og Yj., =, = =,, > =,, =, + (,,, ), > =. 39 Enten er xi og yj like eller ikke. Hvis de er det skal xi=yj=zk være med. Ellers vil Z være en LCS enten av Xi-1 og Y eller av X og Yj-1. Vi vet ikke hvilken, men prøver begge og velger den største.
Rekursjon? Enten vi gjør det rekursivt eller iterativt: Legg svarene i en tabell. 40
(,,, ),, =,, +,,,,,,,,, I b-tabellen lagrer vi en referanse til hvor vi «kom fra». 41
42
X nedover til venstre, Y bortover på toppen. Nedoverpil: Dropp en bokstav fra X vekt 0. Bortoverpil: Dropp en bokstav fra Y vekt 0. Skråpil: Ta med bokstav fra X/Y: Vekt 1. Finn lengste vei fra øverst t.v. til nederst t.h. Dette er rett og slett DAG Shortest Path (eller Longest Path, da som jo blir like lett for DAG-er). 43
(,,, ) = =, = (,,, ), = (,,, ) (,,, ) 44
Egenskaper bak DP Optimal substruktur: En optimal løsning bygger på optimale løsninger på delproblemer Overlappende delproblemer: Fordi flere problemer deler delproblemer lønner det seg å lagre dem 45 Korteste vei? Har begge deler. Lengste vei (uten sykler)? Har ikke optimal substruktur Hvis vi ikke har overlappende delproblemer *kan* vi bruke DP, men det er egentlig ingen vits det blir bare splitt-og-hersk med unødvendig lagring av delproblemer.
2 1 2 2 ) @ < 2 Korteste vei oppdeling i delproblemer som må optimaliseres. Korteste veier består av korteste del-veier. 46
A * Lengste vei. Betrakt q-r-t, en maksimal sti fra q til t. Består den av lengste vei fra q til r og fra r til t? *Nei*! Vi kan ikke bruke DP (og har ingen annen god løsning heller). - ( 47