570 likes | 798 Views
Dinamikus programozás. Szlávi Péter ELTE IK szlavi@ludens.elte.hu. Dinamikus programozás * tartalom. 0 Bevezetés 1 Egy gondolatébresztő példa 2 Első példázat * pénzváltás 3 Második példázat * optimális pénzváltás 4 Harmadik példázat * tükörszavak 5 Irodalom. 0 Bevezetés.
E N D
Dinamikus programozás Szlávi Péter ELTE IK szlavi@ludens.elte.hu
Dinamikus programozás* tartalom 0 Bevezetés 1 Egy gondolatébresztő példa 2 Első példázat * pénzváltás 3 Második példázat * optimális pénzváltás 4 Harmadik példázat * tükörszavak 5 Irodalom Szlávi Péter: Dinamikus programozás
0 Bevezetés • A lényeg: Valamilyen probléma (optimális) megoldása úgy, hogy • rekurzívan visszavezetjük rész-problémák megoldására, de • a rekurzió elkerülését (minimális-ra szorítását) egy táblázat felépíté-sével, és újrahasznosításával érjük el… Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa 1.1 Az „iskolapélda” – pénzfelválthatóság Bemenete: P={p1,...,pN} pozitív egészek – a pénzcímletek, és E pozitív egész – a felváltandó összeg Kimenete: FelválthatóE logikai érték – jelentése = fel- váltható-e az E a P halmazban felsorolt cím- letekkel úgy, hogy minden címletet legfeljebb egyszer használunk fel Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa 1.2 A példa „ízlelgetése” A felváltás „szerkezetének” elemzése Egy logikus rekurzív kapcsolat: • Tfh. felváltható az E, ekkor • (1a) E = pi1+…+pik , • feltehető: • (1b) i1<…<ik is. • Ez esetben világos, hogy • E–pik = pi1+…+pik-1 • leírása az E–pik és {p1,…,pik-1} paraméterek- • kel jellemzett redukált feladatnak Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Részproblémákra bontás A felhasználható címleteket rögzített sorrendűnek tekintve a {p1,…,pi} hal-mazt egyértelműen azonosíthatjuk i-vel. Így bármely (rész)probléma azonosítható az (X,i) paraméter-kettőssel, ahol X a felváltandó összeg és i a felváltáshoz felhasználható címletek utol- sójának indexe A feladat: (E,N). A (2)-ben megfogal-mazott részfeladat: (E-pik,ik-1). Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Rekurzív összefüggések a részproblé-mák és megoldásaik között(vázlatosan) • FV: N N L • FV(X,i) = Igaz, ha • pi=X, vagy • pi<X és FV(X-pi,i-1), vagy • FV(X,i-1) i. az éppen szükséges címlet i. felhasználható és a mara-dék felváltható az előzőekkel i. nélkül, az előzőekkel felváltható Szlávi Péter: Dinamikus programozás
ì > Ù = Ú i 0 X p i ï = > Ù < Ù Ú FV(X, i) : i 1 X FV(X - p , i - 1) p í i i ï > Ù i 1 FV(X, i - 1) î 1 Egy gondolatébresztő példa Rekurzív megoldás egy lehetséges algoritmusa type TCimletek=record db:integer; cimlet: array [1..MaxCimletDb] of integer end; var Cimletek:TCimletek; function FV(const X{felváltandó}, i{max.index}:integer):boolean; begin FV:=((i>0) and (Cimletek.cimlet[i]=X))//i. éppen a kellő címlet or ((i>1) and FV(X,i-1)); //nem az, de i-1.-ig felváltható or ((i>1) and (Cimletek.cimlet[i]<X) and//i. felhasználható FV(X-Cimletek.cimlet[i],i-1)) //és a maradék i-1.-ig felváltható end;//FV Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Próbák – elemzések: • Kis címletszám (pl. {1,2,5}) mellett • „igenlő” a megoldás (pl. 8) – hívási sorrend • „tagadó” a megoldás (pl. 9) – hívási sorrend • mindkét végeredményhez olyan ada-tok alapján, amelyben van ismétlődő címlet – hívási sorrend, hívás-szám • Különféle címletszám (pl. 5, 9, 15, …) mellett olyan összeg, amely azért nem váltható fel, mert túl nagy – hívás-szám növekedése Próbáljuk ki és következtessünk!Zip, exe Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa a) tesztek … FV:=((i>0) and (Cimletek.cimlet[i]=X))//i. éppen a kellő címlet or ((i>1) and FV(X,i-1)); //nem az, de i-1.-ig felváltható or ((i>1) and (Cimletek.cimlet[i]<X) and//i. felhasználható FV(X-Cimletek.cimlet[i],i-1)) //és a maradék i-1.-ig felváltható … Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa • tesztek • (folytatás) … FV:=((i>0) and (Cimletek.cimlet[i]=X))//i. éppen a kellő címlet or ((i>1) and FV(X,i-1)); //nem az, de i-1.-ig felváltható or ((i>1) and (Cimletek.cimlet[i]<X) and//i. felhasználható FV(X-Cimletek.cimlet[i],i-1)) //és a maradék i-1.-ig felváltható … Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Tapasztalatok: • A hívások módszeresen következnek egy-másután. Akár iterációval is „utánozhat-nánk”. (Legalábbis az ismétlésmentes esetben.) • Az ismétlésmentes esetekben a hívás-szá-mok legfeljebb 1 értékűek, azaz legfeljebb egyszeres számolást jeleznek, ami a haté-konyság szempontjából megnyugtató. A 3. futásnál is még legfeljebb 2 az ismétlődő számítás, de a 4.-nél, ami alig különbözik a 3.-tól, már 4 helyen is „tripletet” látunk. S ez rosszat sejtet. kód Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa • A hívások során egy bináris fát „járunk be”. Pl. a „9 összeg {1,2,5} címletekkel” futáshoz tartozó bináris fa. … FV:=((i>0) and (Cimletek.cimlet[i]=X))//i. éppen a kellő címlet or ((i>1) and FV(X,i-1)); //nem az, de i-1.-ig felváltható or ((i>1) and (Cimletek.cimlet[i]<X) and//i. felhasználható FV(X-Cimletek.cimlet[i],i-1)) //és a maradék i-1.-ig felváltható … kód Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa • tesztek Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Újabb tapasztalatok: • Durván növekszik a hívás-szám (mindkét) paraméter növekedtével. • A legrosszabb (negatív végeredményű) esetekben a hívás-számokra „gyanús” értékeket kaptunk. Állítás: Ha RekHDb(X,i) az X összeg felbonthatósá-gához szükségez rekurzív hívások számátjelenti (i. címlettel bezárólag), akkor legked-vezőtlenebb esetben a szükséges rekurzív hívások száma: RekHDb(X,i) = 2i–1 • A hívás-szám maximumát igenlő esetben is elérhetjük. Példát erre láss itt! Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Röviden: DP. A dinamikus programozásos megoldás Táblázatba gyűjtjük a részproblé-mákra adott válaszokat. A táblázat sorai az egyes X összegek-hez, oszlopai az egyes pi címletekhez rendeli az FV(X,i) értékeket. Éppúgy, ahogy az előbbi programnál tettünk, csakhogy ott tisztán adminisztratív, működés-megértési céllal. A táblázatkitöltést a kis értékek felöl kezdjük: hiszen az FV(X,i) rekurzió-jában FV(X,i–1) és FV(X–pi,i–1) szere-pel. Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa A megoldó kód vázlata: Az sgRekTab jelenti most a táblázatot: function PenzValtas_DinProg:boolean; begin Tablafeltoltes(Felvaltando,Cimletek.db); PenzValtas_DinProg:=sgRekTab.Cells[Cimletek.db+1, Felvaltando+2]='+'; end; Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa procedure Tablafeltoltes (const E{felváltandó}, N{max.index}:integer); var i,x:integer; begin with fmPenzValtas do begin for x:=1 to E do begin sgRekTab.Cells[2,x+2]:='-';//első oszlop (=2 indexű) Hamis end;//for x //kivéve az 1. cimletnél: if Cimletek.cimlet[1]<=E then //van még cimlet[1]-dik sor? begin sgRekTab.Cells[2,Cimletek.cimlet[1]+2]:='+'; end;//if … Szlávi Péter: Dinamikus programozás
… FV:=((i>0) and (Cimletek.cimlet[i]=X))//i. éppen a kellő címlet or ((i>1) and FV(X,i-1)); //nem az, de i-1.-ig felváltható or ((i>1) and (Cimletek.cimlet[i]<X) and//i. felhasználható FV(X-Cimletek.cimlet[i],i-1)) //és a maradék i-1.-ig felváltható … 1 Egy gondolatébresztő példa Rekurzív hívás helyett táblahasználat … for i:=2 to N do//az i. oszlop számítása begin for x:=1 to E do begin if (Cimletek.cimlet[i]=x) or (sgRekTab.Cells[i,x+2]='+')or ((Cimletek.cimlet[i]<x) and (sgRekTab.Cells[i,x-Cimletek.cimlet[i]+2]='+')) then sgRekTab.Cells[i+1,x+2]:='+‘//igaz else sgRekTab.Cells[i+1,x+2]:='-'//hamis {endIf}; end;//for x end;//for i end;//with end;//Tablafeltoltes kód Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Összehasonlító futás: Próbáljuk ki és következtessünk! Zip, exe Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Megjegyzések: • A rekurzív megoldás fajlagos ismétlési száma: 1 048 575 / 25 267 41 . • A DP 222 220 darab táblaelemet szá-mol ki, de csak egyszer. • A fajlagos sebesség növekedés: 1 048 575 / 222 220 4,7 . • A „feleslegesen” kiszámolt táblaelem szám: (222 220 – 25 267) = 196 953 7,8 szorosa a szükségesnek. Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Egy „okosabb” DP megoldás Ötlet: ötvözni a rekurzív megoldás célratörését, azaz „csak azt kiszámol-ni, amit muszáj” elvét a DP megoldás „mindent csak egyszer kiszámolni” elvével. Tehát a számítás logikája rekurzív marad, de mielőtt egy rekurzív hívást kezdeményeznénk, megnézzük, nem lett-e már kiszámolva. Szlávi Péter: Dinamikus programozás
még nem ismert a válasz 1 Egy gondolatébresztő példa már ismert a '+' válasz function FV(const X,i:integer):boolean; begin if (fmPenzValtas.sgRekTab.Cells[i+1,X+2]='+') then begin FV:=true endelseif (fmPenzValtas.sgRekTab.Cells[i+1,X+2]='-') then begin FV:=false end elsebegin FV:=((i>0) and (Cimletek.cimlet[i]=X)) or ((i>1) and FV(X,i-1)) or ((i>1) and (Cimletek.cimlet[i]<X) and FV(X-Cimletek.cimlet[i],i-1)) end {endif}; end;//FV már ismert a ‘-' válasz kód Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa Összehasonlító futás: Próbáljuk ki és következtessünk! Zip, exe Szlávi Péter: Dinamikus programozás
1 Egy gondolatébresztő példa 1.3 A DP módszerének váza • A megoldás szerkezetének tanulmányozása – részproblémákra bontás megsejtése • Részproblémákra és összetevőkre bontás– részproblémák és paramétereik körvonala-zása: a rekurzió előkészítése • Részproblémák megoldásának kifejezése rekurzívan az összetevők megoldásaiból– formalizálás: függvénydefiníció • Részproblémák megoldásának kiszámítása – a táblaszámítás algoritmizálása • kiszámítási sorrend meghatározása: minden részprob-léma minden összetevője előbb szerepeljen a felsorolás-ban • az „alulról-felfelé” haladó számítás • A megoldás előállítása a 4. lépésben előállított táblázat segítségével– a megoldás algoritmizálása Szlávi Péter: Dinamikus programozás
2 Első példázat – pénzváltás 2.1 A feladat Bemenete: P={p1,...,pN} pozitív egészek – a pénzcímletek, és E pozitív egész – a felváltandó összeg Kimenete: SP – a felváltásban szereplő pénzcímletek; az S halmazban felsorolt címleteket legfeljebb egyszer használhatjuk fel Szlávi Péter: Dinamikus programozás
2 Első példázat – pénzváltás 2.2 A megoldás 2.2.1 A megoldás szerkezetének tanulmányozása Ua. mint korábban… Szlávi Péter: Dinamikus programozás
2 Első példázat – pénzváltás 2.2.2 Részproblémákra és összetevők-re bontás A részproblémák a korábbiakhoz hason-lóan fogalmazhatók meg. Az FV(X,i) jelentése viszont más: a legna-gyobb P-beli elem indexe, amely még előfordul az X felváltásában. Pl.: P={2,4,5} N=3; X=7, akkor S={2,5} FV(7,3)=3, mert p3=5, FV(7-p3,3-1)=FV(7-5,3-1)=1, mert p1=2, FV(2-p1,1-1)=FV(2-2,1-1)=FV(0,0). Szlávi Péter: Dinamikus programozás
2 Első példázat – pénzváltás 2.2.3 Részproblémák megoldásának kifejezése Vegyük észre, hogy akkor N+1 az ered-mény, ha nincs megoldás, s o, ha már nem kell folytatni. Szlávi Péter: Dinamikus programozás
2 Első példázat – pénzváltás 2.2.4 Részproblémák megoldásának kiszámítása A FV definíciójábóllátszik: csökkenő pa-raméterekhez nyúl vissza, így atáblaki-töltő számítás kis értékektől indulhat a nagyobbak felé… Szlávi Péter: Dinamikus programozás
2 Első példázat – pénzváltás 2.2.5 A megoldás előállítása A megoldás meghatározása most bonyodalmasabb, mint volt korábban: hiszen most egy indexet kapunk a függvény ér-tékeként (k1=FV(E,N)). A táblá-zatból kiolvasható a követke-zőé (k2=FV(E–pk1,k1–1)), majd az azt követőé éít. Amíg a fel-váltandó összegparaméter 0-ra nem csökken. Rekurzív megoldás esetén persze ez a visszalépdelés is rekurzívan történne. Szlávi Péter: Dinamikus programozás
2 Első példázat – pénzváltás Az sgRekTab-ban az FV-értékek; a KiCimletek-ben képződik az eredmény begin//PenzValtas_DinProg Tablafeltoltes(Felvaltando,Cimletek.db); KiCimletek.db:=0; ifstrToInt(sgRekTab.Cells[Cimletek.db+1,Felvaltando+2])<=Cimletek.dbthen begin kX:=Felvaltando; k:=Cimletek.db; while kX>0 do begin k:=strToInt(sgRekTab.Cells[k+1,kX+2]); inc(KiCimletek.db); KiCimletek.cimlet[KiCimletek.db]:=Cimletek.cimlet[k]; kX:=kX-Cimletek.cimlet[k]; dec(k); end;//while end;//if end;//PenzValtas_DinProg van megoldás: leg-alább egy címlet kX felváltásához szükséges legnagyobb címlet indexe: k kX: a maradék összeg k. címlet már nem lehet, legfeljebb kisebb indexű Szlávi Péter: Dinamikus programozás
2 Első példázat – pénzváltás Rekurzív DP Összehasonlító futás: „okos” DP Próbáljuk ki és következtessünk! Rekurzív: Zip, exe; DP: Zip, exe;„okos” DP: Zip, exe. Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás 3.1 A feladat Bemenete: P={p1,...,pN} pozitív egészek – a pénzcímletek, és E pozitív egész – a felváltandó összeg Kimenete: SP – a felváltásban szereplő pénzcímletek; az S halmazban felsorolt címleteket legfeljebb egyszer használhatjuk fel; S a lehető legkisebb elemszámú Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás 3.2 A megoldás … és nem lehetne „mohóskodni”… ? A problémánkhoz illeszkedő mohó választás: a még választhatók közül a legnagyobb címlet. Egy ellenpélda: P={5,4,4,1,1,1} és E=8; a mohó megoldás: 8=5+1+1+1, ennél jobb: 8=4+4. Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás 3.2.1 A megoldás szerkezetének tanulmányozása Ua. mint korábban… Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás 3.2.2 Részproblémákra és összetevők-re bontás A részproblémák a korábbiakhoz hason-lóan fogalmazhatók meg. Két lépésben oldjuk meg a feladatot. • Az Opt(X,i) jelentése: X felváltásához szükséges (első i közül választható) címletek száma. • Az FV(X,i) jelentése: a legnagyobb P-beli elem indexe (i), amely még elő-fordul a X felváltásában. (Építünk az Opt-ra.) Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás 3.2.3 Részproblémák megoldásának kifejezése Vegyük észre, hogy akkor N+1 az ered-mény, ha nincs megoldás; 0, ha célhoz értünk. Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás FV Egy váratlan probléma: Opt A futás adminisztrálását végző táblapár nincs szinkron-ban. Bajt okoz, hogy a bal-felső tábla (1,2) eleme üres. Pedig az alkalmazás foglalkozott vele, hiszen a bal-alsó tábla (1,2) cellája helyesen 1 értéket tartalmaz. Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás A probléma magyarázata: Az FV definíciójának optimumra hivatko-zó rekurzív (3.) ágánál tartunk, „készen kapja” a döntéséhez szükséges informá-ciót. Ezért nem bontogatja le sem az (X–pi,i–1), sem az (X,i–1) részproblémákra; így a megoldás alapjául szolgáló, admi-nisztratív táblázat ezen elemei kitöltet-lenek maradnak; és a címleteket összeszedő részben katasz-trófát okoz. Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás A probléma megoldása: Az optimum kiszámításra többlet admi-nisztrációt kell bízni: feljegyzi az FV-hez tartozó táblázatba az általa e pil-lanatban még ismert információt, hogy hányadik címlet szerepel a felbontás-ban. Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás 3.2.4 Részproblémák megoldásának kiszámítása A táblázatgenerálás sorrendje: A címletek szerint „alulról fölfelé” halad-va, de az érték szerint fordítva. A fordított irány magyarázatául: • az optimumot kiszámoló függvényhez tar-tozó táblázatot megspórolhatjuk (nincs szükség rá a végeredmény generálásához); • mivel csak az előző címlet oszlopára hivat-kozik, elegendő azt és az éppen számítás alatt állót megtartani, sőt • egyetlen oszlop is elegendő (lenne:-), ha a kiszámítás sorrendjét megfordítjuk. Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás 3.2.5 A megoldás előállítása A megoldás meghatározása most az előző-vel megegyező módon történik. Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás az „okos” DP szokásos jelzője A puding próbája: Az alábbi táblázat összefoglalja a re-kurzív és a memorizálós DP alkal-mazás rekurzív hívásainak számát az {1,2,5,10,20,50,100,200,500,1000,1,2,5,10,20,50,100,200,500,1000} címletek esetén: FV + Opt E FV Opt Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás A nem optimális, rekurzív megoldás Az optimális, rekurzív megoldás Összehasonlító futás: Próbáljuk ki és elemezzük! Rekurzív: Zip, exe; DP: Zip, exe; „okos” DP: Zip, exe. Szlávi Péter: Dinamikus programozás
3 Második példázat – optimális pénzváltás Megjegyzések: • Kitöltött táblaelemek száma kicsivel több, mint a nem optimális megoldást kereső esetében. (Mindkét táblát figyelem-be véve valamivel több, mint kétszerese.) • FV rekurzív hívások száma minimális. Az FV-hez tartozó táblázat kitöltését döntően az Opt függvény végzi. • A rekurzív hívások száma kisebb az optimumra nem törekvőénél. • Sokkal kevésbé nő az össz rekurzív hívások száma az előbbinél. Szlávi Péter: Dinamikus programozás
4 Harmadik példázat – tükörszavak 4.1 A feladat Bemenete: szó={b1,...,bN} szó – jelek sorozata Kimenete: bj természetes szám – minimálisan ennyi jel beillesztésével tehető a szó palindrommá (tükörszóvá). Szlávi Péter: Dinamikus programozás
4 Harmadik példázat – tükörszavak 4.2 A megoldás 4.2.1 A megoldás szerkezetének tanulmányozása TSz(S): az a szöveg, amely minimális számú jel beillesztésével képződik az S-ből. Ilyen biztosan van: S&S’, ahol S’ az S megfordítása. Szlávi Péter: Dinamikus programozás
4 Harmadik példázat – tükörszavak Esetek: • Ha S=, akkor TSz(S)==S. • Ha S egy jelből áll, akkor maga is tükörszó, azaz TSz(S)=S. • Legyen S=x&R&y, ahol x, y az S első és utolsó jele, és R akár üres is lehet. • Ha x=y, akkor TSz(S)=x&TSz(R)&y. … Szlávi Péter: Dinamikus programozás
4 Harmadik példázat – tükörszavak … • Ha xy, akkor TSz(S) első és utolsó jele vagy x vagy y. • Ha TSz(S)=x&U&x, ekkor x-et szúr-tunk be a végére, azaz U=TSz(R&y). • Ha TSz(S)=y&U&y, ekkor y-t szúrtunk be az elejére, azaz U=TSz(x&R). Vagyis U gyanánt (ami eggyel rövidebb S-nél) a TSz(R&y) és a TSz(x&R) közül azt kell választani, amely kevesebb beszúrással kapható meg. Szlávi Péter: Dinamikus programozás