2 dalis - techmat.vgtu.lt
2 dalis - techmat.vgtu.lt
2 dalis - techmat.vgtu.lt
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Algoritmų sudarymo principai ir metodai<br />
Algoritmų analizės specialieji skyriai<br />
doc. dr. Vadimas Starikovičius<br />
VGTU Matematinio modeliavimo katedra<br />
VGTU SC Lygiagrečiųjų skaičiavimų laboratorija<br />
Paskaitų kursas. 2-oji <strong>dalis</strong>.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Turinys<br />
1 Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Tai bendras daugelio uždavinių sprendimo algortimų sudarymo<br />
principas, kai sprendinį galima rasti patikrinus baigtinį<br />
variantų skaičių. Šis metodas ypač išpopuliarėjo, kai atsirado<br />
kompiuteriai. Sudarant konkretų algoritmą, iškyla 2 uždaviniai:<br />
1 Kaip gauti visus įmanomus variantus?<br />
2 Kaip sumažinti tikrinamų variantų skaičių, nes tiesioginis<br />
(pilnas) visų variantų patikrinimas gali būti praktiškai<br />
neįvykdomas net su greičiausiais superkompiuteriais?<br />
Šių uždavinių sprendimui naudojami įvairiausi metodai:<br />
1 specialūs kombinatorikos algoritmai, rekursija, ...<br />
2 šakų ir rėžių, dinaminio programavimo metodai, euristikos.<br />
Atvirkštinis pavyzdys: informacijos kodavimas ir jos dešifravimas.<br />
Informacija turi būti užkoduota taip, kad jos dešifravimui nebūtų<br />
galima sudaryti algoritmo su mažu variantų skaičiumi.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Rekursijos metodas<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Rekursija yra plačiai naudojama apibrėžiant matematinius<br />
objektus, sudarant bei realizuojant įvairiausius algoritmus.<br />
Rekursijos schema<br />
Objektas, priklausantis nuo parametro, yra apibrėžiamas<br />
naudojant tą patį objektą ar objektus, tik su kitomis<br />
parametro reikšmėmis.<br />
Nurodoma rekursijos pabaiga ir nustatomos pradinės<br />
sąlygos. Šių sąlygų skaičius sutampa su rekursijos gyliu.<br />
Pavyzdys. Fibonačio skaičiai (it. Leonardo Fibonaci).<br />
Aptinkami įvairiuose informatikos algoritmuose. Jie apibrėžiami<br />
tokiu būdu:<br />
{<br />
fn−1 + f n−2 , jei n > 1,<br />
f n =<br />
f 0 = 1, f 1 = 1 .<br />
doc. dr. Vadimas Starikovičius Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Rekursinis Fibonačio skaičių radimo algoritmas<br />
Kai objektas (uždavinys) apibrėžiamas rekursijos pagalba, lengvai<br />
gaunamas objekto radimo (uždavinio sprendimo) rekursinis<br />
algortimas.<br />
int Fib (n)<br />
begin<br />
(1) if ( n < 2 ) return (1);<br />
else<br />
(2) return<br />
end if<br />
end Fib<br />
(<br />
Fib(n-1) + Fib(n-2)<br />
Rekursinio algoritmo vykdymo eiga, kai n = 4 ir n = 20:<br />
)<br />
;<br />
Daug kartų skaičiuojame tas pačias reikšmes!<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Rekursinio Fibonačio skaičių algoritmo sudėtingumas<br />
Bazine algoritmo operacija laikykime sudėtį ir ignoruokime<br />
papildomas sąnaudas, atsirandančias realizuojant rekursijos<br />
kreipinius (praktijoje vis dė<strong>lt</strong>o šios sąnaudos pasirodo gana<br />
didelės). Gauname tokią rekurentinę lygtį ir pradines sąlygas:<br />
⎧<br />
⎨T(n) = T(n − 1) + T(n − 2) + 1,<br />
⎩T(0) = 1, T(1) = 1.<br />
Atlikę skaičiavimus, randame funkciją T(n):<br />
√<br />
( 1 + 5<br />
T(n) = c<br />
2<br />
) n<br />
+ (2 − c)<br />
( 1 −<br />
√<br />
5<br />
2<br />
√<br />
) n ( 1 + 5 ) n<br />
− 1 ≈ c .<br />
2<br />
Taigi rekursinis Fibonačio algoritmas yra eksponentinio<br />
sudėtingumo. Padidėjus vienetu duomenų skaičiui n,<br />
algoritmo vykdymo eiga pailgėja (1 + √ 5)/2 = 1, 618 kartų.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Rekursinio Fibonačio skaičių radimo algoritmo<br />
skaičiavimo eksperimentas<br />
Šią teorinę išvadą patvirtina ir atlikto skaičiavimo<br />
eksperimento rezu<strong>lt</strong>atai:<br />
n skaičiavimo laikas T n ρ n = T n<br />
T n−1<br />
40 2,88 1,610<br />
41 4,68 1,625<br />
42 7,57 1,617<br />
43 12,25 1,618<br />
Atlikta analizė rodo, kad dideliems n, rekurisnis algoritmas<br />
praktiškai nenaudotinas (T(100) ≈ 317000 metų). Kaip dar<br />
galima rasti Fibonačio skaičius?<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Iteracinis Fibonačio skaičių radimo algoritmas<br />
Fibonačio skaičius galime rasti ir iteraciniu algoritmu:<br />
FibIter (n)<br />
begin<br />
(1) f2 = 1; f1 = 1; Fib = 1;<br />
(2) for ( i = 2; i
Algoritmų sudarymo principai ir metodai<br />
Kada reikalinga rekursija?<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Naudojant rekursiją, patogu kontroliuoti užduočių atlikimo eiliškumą,<br />
kai to reikalauja sprendžiamas uždavinys. Pavyzdžiui, dvejetainio<br />
medžio viršūnių aplankymo algoritmai: prefix, infix ir postfix.<br />
Prefix (node* tree)<br />
begin<br />
(1) if ( tree != NULL )<br />
(2) print(tree->data);<br />
(3) Prefix (tree->left);<br />
(4) Prefix (tree->right);<br />
end if<br />
end Prefix<br />
Infix (node* tree)<br />
begin<br />
(1) if ( tree != NULL )<br />
(2) Infix (tree->left);<br />
(3) print(tree->data);<br />
(4) Infix (tree->right);<br />
end if<br />
end Infix<br />
Postfix (node* tree)<br />
begin<br />
(1) if ( tree != NULL )<br />
(2) Postfix (tree->left);<br />
(3) Postfix (tree->right);<br />
(4) print(tree->data);<br />
end if<br />
end Postfix<br />
Pavyzdys. Tarkime, aritmetinė išraiška<br />
(a − b ∗ c)(d ∗ e + f ) saugoma dvejetainiame medyje.<br />
Tada, naudodami Prefix, Infix ir Postfix algoritmus,<br />
gauname tokias šios išraiškos formas:<br />
a) prefix: ∗ − a ∗ bc + ∗def , b) infix: a − b ∗ c ∗ d ∗ e + f ,<br />
c) postfix: abc ∗ −de ∗ f + ∗.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas grįžtant atgal<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Rekursija yra labai naudinga sprendžiant uždavinius variantų<br />
perrinkimu su grįžimu atgal (angl. backtrack). Pavyzdžiui,<br />
1) Kaip pereiti per labirintą? 2) Žirgo maršrutas šachmatų lentoje?<br />
Sudarysime rekursinį algortimų šabloną (angl. template)<br />
tokių uždavinių sprendimui.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Variantų perrinkimo šablonas grįžtant atgal<br />
Sprendžiant konkretų uždavinį turime apibrėžti duomenų struktūrą pozicija,<br />
kurioje saugosime informaciją apie uždavinio sprendimo eigą (pvz., praeitą<br />
maršrutą labirinte arba šachmatų lentoje).<br />
Sprendinio paieška tęsiama iš P taško (pvz., P - lentos langelis).<br />
Turime apibrėžti funkciją S=BandymųAibė(P, pozicija), kuri generuoja<br />
visus naujus ėjimus, kuriuos galima atlikti iš taško P. Leistinų ėjimų aibę S<br />
apibrėžia uždavinio sąlygos ir duomenų struktūroje pozicija saugoma<br />
informacija apie jau aplankytas paieškos vietas.<br />
Cikle pasirenkame vieną po kito ėjimus iš S, kiekvienam gauname naują<br />
tašką U, kurį įtraukiame į pozicija, ir gautai naujai pozicijai rekursyviai<br />
kviečiame pagrindinę algoritmo funkciją (variantų perrinkimo šabloną).<br />
Jei padarę kažkurį ėjimą gauname, kad naujos pozicijos S yra tuščia arba<br />
netiko nei vienas iš naujos S ėjimų (pranešime apie tai grąžindami reikšmę<br />
0), tai turime grįžti atgal, atstatyti seną poziciją (SenaPozicija(U, pozicija))<br />
ir tikrinti kitą leistiną ėjimą.<br />
Kai surandame sprendinį RadomeSprendinį (pozicija) == taip, grąžiname<br />
reikšmę 1, taip panešdami šią funkciją iškvietusiai funkcijai, kad sprendinys<br />
rastas ir ji irgi gali nutraukti savo darbą grąžindama 1.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Rekursinis algortimų šablonas<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
int Tikrink (int n, Point P, Inf pozicija)<br />
begin<br />
(1) if ( RadomeSprendinį (pozicija) == taip ) then<br />
(2) Spausdink (pozicija);<br />
(3) return(1);<br />
(4) else<br />
(5) S = BandymųAibė(P, pozicija)<br />
(6) while ( S ≠ ∅ ) do<br />
(7) U = NaujasBandymas(S);<br />
(8) NaujaPozicija(U, pozicija);<br />
(9) if ( Tikrink (n+1, U, pozicija) == 1 ) return (1);<br />
(10) else<br />
(11) SenaPozicija(U, pozicija);<br />
end if<br />
end do<br />
(12) return (0);<br />
end if<br />
end<br />
Tikrink<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Skaldyk ir valdyk metodas<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Daugelio uždavinių efektyvius sprendimo algoritmus sudarome<br />
tokiu metodu:<br />
1 Uždavinį skaidome į kelis mažesnius uždavinius.<br />
2 Randame šių uždavinių sprendinius.<br />
3 Iš jų sudarome viso uždavinio sprendinį.<br />
Dalinius uždavinius vėl galime spręsti tokiu pačiu metodu. Taip<br />
skaidome tol, kol gautieji uždaviniai yra lengvai išsprendžiami.<br />
Taip gauname rekursinį skaldyk ir valdyk metodo (angl.<br />
divide and conquer) algoritmą.<br />
Sprendžiant konkretų uždavinį reikia apibrėžti, kaip<br />
realizuojami šie trys žingsniai. Tai galima daryti įvairiai, todėl<br />
dažnai tam pačiam uždaviniui skaldyk ir valdyk metodu galime<br />
sudaryti kelis skirtingus sprendimo algoritmus.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Rekursinių skaldyk ir valdyk algortimų šablonas<br />
Sprendžiame uždavinį, kurį apibūdina duomenų struktūrą A.<br />
SprendTipas SkaldykIrValdyk (Inf A)<br />
begin<br />
(1) if ( |A| > ε ) then<br />
(2) (A 1 , A 2 , . . . , A M ) = Skaldyk (A);<br />
(3) for all ( A j , j=1, 2,…, M ) do<br />
(4) S j = SkaldykIrValdyk (A j );<br />
end do<br />
(5) S = Valdyk (S 1 , S 2 , . . . , S M );<br />
else<br />
(6) S = Sprendinys(A)<br />
end if<br />
(7) return (S);<br />
end SkaldykIrValdyk<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Rekursinių skaldyk ir valdyk algortimų sudėtingumas<br />
Tarkime, kad n dydžio uždavinį dalijame į a mažesnių<br />
uždavinių, kurių dydis yra n/b, o atskirų sprendinių sujungimo<br />
sąnaudos yra d(n).<br />
Kai uždavinys yra mažas, t. y. n = 1, jį išsprenžiame kokiu nors<br />
paprastu algoritmu, o veiksmų skaičių žymėsime c.<br />
Tokio algoritmo sudėtingumo funkcija tenkina uždavinį:<br />
⎧<br />
⎨c, jei n = 1 ,<br />
T(n) =<br />
⎩aT(n/b) + d(n), jei n > 1 .<br />
Kai n = b m , jo sprendinį jau apskaičiavome:<br />
T(n) = ca m + ∑ m−1<br />
j=0 aj d(b m−j ).<br />
Jei, a = 2, b = 2, d = gn, tai skaldyk ir valdyk algoritmo<br />
sudėtingumo funkcijaT(n) = O(n log n).<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Pavyzdys. Dvieju gretimų taškų radimas.<br />
Turime n = 2 m taškų aibę<br />
P(n) = {P j = (x j , y j ), j = 1, 2, . . . , n}.<br />
Atstumą tarp dviejų taškų P i ir P j apibrėžiame lygybe<br />
d(P i , P j ) = ( (x i − x j ) 2 + (y i − y j ) 2) 1/2 .<br />
Reikia rasti tokius du taškus P q ir P r , tarp kurių atstumas yra<br />
mažiausias<br />
d(P q , P r ) = min d(P i, P j ).<br />
1≤i,j≤n<br />
Koks yra pilno taškų porų perrinkimo algoritmo<br />
sudėtingumas? Iš viso galime sudaryti n(n−1)<br />
2<br />
skirtingas taškų<br />
poras, todėl tokio algoritmo sudėtingumas yra O(n 2 ).<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Skaldyk ir valdyk metodu sudarykime šio uždavinio sprendimo<br />
algortimą. Sunumeruokime taškus koordinatės x didėjimo<br />
tvarka: x 1 ≤ x 2 ≤ . . . ≤ x n .<br />
Padalinkime visus taškus į dvi vienodo dydžio aibes:<br />
(n ) {<br />
P L = Pj , j = 1, 2, . . . , n } ,<br />
2 2<br />
(n ) {<br />
P R = Pj , j = n 2<br />
2 + 1, 2, . . . , n} .<br />
Tada teisingas vienas iš šių teiginių:<br />
1 Abu taškai P q , P r priklauso aibei P L<br />
( n<br />
2<br />
) .<br />
2 Abu taškai P q , P r priklauso aibei P R<br />
( n<br />
2<br />
) .<br />
3 Taškas P q priklauso aibei P L<br />
( n<br />
2<br />
) , o taškas Pr priklauso<br />
aibei P R<br />
( n<br />
2<br />
) .<br />
Taigi, galime taikyti rekursinių skaldyk ir valdyk algortimų<br />
šabloną.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
float GretimiTaškai (Set P, int n)<br />
begin<br />
(1) if ( n > 2 )<br />
(2) p L = GretimiTaškai (P L , n 2 );<br />
(3) p R = GretimiTaškai (P R , n 2 );<br />
(4) p T = min(p L , p R );<br />
(5) p = Pasienis (P L , P R , p T );<br />
else<br />
(6) p = d (P 1 , P 2 );<br />
end if<br />
(7) return (p);<br />
end GretimiTaškai<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Dabar pateiksime procedūros Pasienis realizaciją. Užtenka<br />
nagrinėti tik taškus, priklausančius pasienio juostai:<br />
P B (n) = {P j : x n/2+1 − p T < x j < x n/2 + p T , j = s, s + 1, . . . , f }.<br />
float Pasienis (Set P L , Set P R , float p T )<br />
begin<br />
(1) for (i=s; i
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Šakų ir rėžių metodas (angl. branch and bound method)<br />
Perrinkant variantus, skaidant ir sprendžiant mažesnius<br />
po-uždavinius, labai svarbu kuo anksčiau išskirti tuos<br />
variantus (po-uždavinius), kuriems uždavinio sprendinys<br />
tikrai nepriklauso, ir šių variantų (po-uždavinių) toliau<br />
nenagrinėti.<br />
Šakų ir rėžių metodas yra bendras metodas, nurodantis<br />
kaip konstruoti tokius sprendimo algoritmus globaliosios<br />
optimizacijos uždaviniams.<br />
Nagrinėsime funkcijos f (X) minimizavimo uždaroje ir<br />
baigtinėje srityje D uždavinį:<br />
f (X 0 ) = min<br />
X∈D f (X).<br />
Jį žymėsime P(f , D). D vadinama leistinųjų sprendinių<br />
aibe (paieškos aibe) ir gali būti įvairiausių prigimčių.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Šakų ir rėžių metodo pagrindiniai žingsniai<br />
Šakų ir rėžių metode yra 2 pagrindiniai žingsniai, kurie turi būti<br />
apibrėžti sudarant konkretų tam tikro uždavinio sprendimo<br />
algoritmą.<br />
1. Skaidymo (angl. branching) žingsnis. Leistinųjų<br />
sprendinių aibę skaidome į baigtinį skaičių mažesnių aibių:<br />
m⋃<br />
D = D i .<br />
i=1<br />
Tada funkcijos f (X) minimumo paieškos algoritmą patogu<br />
vaizduoti medžio duomenų struktūroje. Medžio šaknyje<br />
užrašome uždavinį P(f , D), šaknies m vaikai apibrėžia<br />
uždavinius P(f , D i ), t. y. funkciją f (X) minimizuojame srityse<br />
D i . Toks skaidymo procesas tęsiamas, kol nesunkiai<br />
apskaičiuojame gautojo uždavinio sprendinį.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
2. Rėžių apskaičiavimo (angl. bounding) žingsnis.<br />
Algoritme turime apibrėžti, kaip efektyviai apskaičiuoti<br />
funkcijos f (X) minimumo srityje D i apatinį LB(f , D i ) ir<br />
viršutinį UB(f , D i ) rėžius:<br />
LB(f , D i ) ≤ min<br />
X∈D i<br />
f (X) ≤ UB(f , D i ).<br />
Tada, žinodami UB(f , D i ), galime apskaičiuoti minimalios<br />
reikšmės f (X 0 ) viršutinį rėžį UB(f , D) visoje aibėje D:<br />
UB(f , D) = min<br />
1≤i≤m UB(f , D i).<br />
Žinodami šiuos rėžius, dažnai galime gerokai sumažinti<br />
nagrinėjamų sričių skaičių. Jeigu srityje D i apatinis f (X)<br />
reikšmių rėžis LB(f , D i ) yra didesnis už UB(f , D):<br />
LB(f , D i ) > UB(f , D), tai tokios srities toliau nebetiriame, nes<br />
joje tikrai nėra optimalaus sprendinio.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Šakų ir rėžių metodo algortimo šablonas<br />
Sudarykime šakų ir rėžių metodo algortimo šabloną.<br />
Tegu visos užduotys saugomos sąraše L.<br />
O geriausias šiuo metu žinomas sprendinys saugomas<br />
struktūroje S. S galėtų būti ir sąrašas, jei reikia išsaugoti<br />
visus gaunamus galimus sprendinius.<br />
Naują užduotį išimame iš sąrašo L, naudodami parinkimo<br />
taisyklę (angl. selection rule). Dažniausiai naudojamas<br />
taisykles aptarsime vėliau.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
begin BranchAndBound ⋃ ()<br />
m<br />
(1) Išskaidome D =<br />
i=1 D i, apskaičiuojame rėžius LB(D i ), UB(D i ),<br />
užduotis P(f , D i ) įtraukiame į sąrašą L = {P(f , D i ), 1 ≤ i ≤ m},<br />
S = ∅, apskaičiuojame UB(D) = min 1≤i≤m UB(D i ).<br />
(2) while (L ≠ ∅) do<br />
(3) Naudodami ( parinkimo ) taisyklę išimame užduotį P(f , D i ) ∈ L<br />
(4) if LB(Di ) < UB(D) then<br />
⋃ m<br />
(5) Išskaidome aibę D i =<br />
j=1 D ij<br />
(6) for all (D ij , j = 1, m) do<br />
(7) Apskaičiuojame ( rėžius UB(D ij ) ir ) LB(D ij )<br />
(8) UB(D) = min UB(D), UB(D ij ) //Galimai patiksliname rėžį<br />
(9) ( ) if LB(D ij ) < UB(D) then<br />
(10) if (P(f , D ij ) yra lapas ) then //Nebeskaidoma sritis<br />
(11) S = Sprendinys(D ij , S) //Ar D ij turi geresnį sprendinį<br />
(12) else // negu turimas S?<br />
(13) L := L ∪ P(f , D ij ) //Įtraukiame į sąrašą<br />
end if<br />
end if<br />
end do<br />
end if<br />
end do<br />
end BranchAndBound<br />
doc. dr. Vadimas Starikovičius Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Dažniausiai naudojamos parinkimo taisyklės<br />
1. Naujausia užduotis. Tiriame užduotį, kurią vėliausiai<br />
sugeneravome. Naudodami tokią strategiją, greitai judame į<br />
variantų medžio gilumą ir minimizuojame saugomų užduočių<br />
skaičių (angl. depth-first search). Sąrašą L realizuojame<br />
naudodami dėklo (angl. stack) duomenų struktūrą.<br />
2. Perspektyviausia užduotis. Tiriame užduotį P(f , D i ),<br />
kurios sprendinių apatinis įvertis LB(f , D i ) yra mažiausias<br />
(angl. best-first search). Tikimės, kad, skaidydami šią užduotį,<br />
greičiau rasime gerus sprendinio artinius arba pavyks iš esmės<br />
sumažinti viršutinį sprendinio įvertį UB(f , D). Tada smarkiai<br />
sumažės ir nagrinėjamų variantų skaičius. Sąrašą L realizuojame<br />
naudodami piramidės (angl. heap) duomenų struktūrą.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Dažniausiai naudojamos parinkimo taisyklės<br />
3. Mažiausio lygio užduotis. Tiriame užduotį P(f , D i ),<br />
kurios lygis medyje yra mažiausias (angl. breath-first search).<br />
Naudodami šią strategiją, tolygiai nagrinėjame visą leistinųjų<br />
sprendinių aibę, t. y. tikimės išvengti detalaus nereikalingų<br />
lokaliųjų minimumų nagrinėjimo. Sąrašą L realizuojame<br />
naudodami eilės (angl. queue) duomenų struktūrą.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Pavyzdys. Globalus Lipšico funkcijos minimumas.<br />
Rasime vienmatės funkcijos f (x) globalų minimumą uždarame<br />
intervale [a, b]:<br />
f (x 0 ) = min<br />
x∈[a,b] f (x).<br />
Tarsime, kad f yra Lipšico funkcija, t. y. egzistuoja konstanta<br />
L, leidžianti įvertinti funkcijos reikšmių skirtumus:<br />
|f (x) − f (y)| ≤ L|x − y|, x, y ∈ [a, b].<br />
Visos tolydžiai diferencijuojamos funkcijos yra ir Lipšico<br />
funkcijos, konstantą L randame imdami funkcijos išvestinės<br />
reikšmių modulio viršutinį rėžį:<br />
|f ′ (x)| ≤ L, x ∈ [a, b].<br />
Visai nebūtina rasti tikslųjį rėžį L, bet kuo mažesnė L reikšmė,<br />
tuo efektyvesnis šakų ir rėžių algoritmas. Pvz., y = sin x, L =?<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Funkcijos minimumo radimo šakų ir rėžių algoritmas<br />
Pagal šakų ir rėžių metodą turime apibrėžti skaidymo žingsnį ir<br />
rėžių apskaičiavimo taisykles.<br />
1. Skaidymo žingsnis. Uždavinio P(f , [a i , b i ]) intervalą<br />
skaidome į du naujus lygius intervalus:<br />
[a i , b i ] = [a i , c i ] ∪ [c i , b i ], c i = a i+b i<br />
2<br />
.<br />
Taip gauname du naujus mažesnius uždavinius P(f , [a i , c i ]) ir<br />
P(f , [c i , b i ]).<br />
Jei b i−a i<br />
2<br />
< ε, kur ε reikalaujamas tikslumas, tai intervalas<br />
toliau nebeskaidomas, o gaunamas uždavinio P(f , [a i , b i ])<br />
sprendinys s i tikslumu ε:<br />
f (s i ) = min(f (a i ), f (c i ), f (b i ))<br />
ir palyginamas su šiuo metu turimu sprendiniu s:<br />
doc. dr. Vadimas Starikovičius<br />
f (s) = min(f (s i ), f (s)).<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Funkcijos minimumo radimo šakų ir rėžių algoritmas<br />
2.1 Viršutinio įverčio skaičiavimo taisyklė. Uždavinio<br />
P(f , [a i , b i ]) sprendinio x 0i viršutinį rėžį UB(f , [a i , b i ]) galima<br />
gauti taip:<br />
f (x 0i ) =<br />
min f (x) ≤ min(f (a i), f (c i ), f (b i )) = UB(f , [a i , b i ]).<br />
x∈[a i ,b i ]<br />
Galima imti ir daugiau intervalo [a i , b i ] vidinių taškų.<br />
2.2 Apatinio įverčio skaičiavimo taisyklė. Uždavinio<br />
P(f , [a i , b i ]) sprendinio x 0i apatinį rėžį LB(f , [a i , b i ]) randame,<br />
taikydami Lipšico funkcijų apibrėžimą:<br />
|f (x 0i ) − f (c i )| ≤ L|x 0i − c i | ≤ L b i−a i<br />
2<br />
.<br />
f (x 0i ) ≥ f (c i ) − L b i−a i<br />
2<br />
= LB(f , [a i , b i ]).<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Lošimų teorijos algoritmai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Daugelį žaidimų galime aprašyti tokia bendra schema:<br />
1. Lošėjai paeiliui atlieka leistinus žaidimo ėjimus. Visą žaidimo<br />
eigą aprašome naudodami medžio duomenų struktūrą. Medžio<br />
viršūnėje saugome pradinę žaidimo poziciją. Viršūnės vaikai<br />
apibrėžia pozicijas, kurias gauname atlikę pirmąjį ėjimą ir t. t.<br />
Medžio lapuose saugome baigiamąsias žaidimo pozicijas.<br />
2. Remdamiesi žaidimo taisyklėmis, galime įvertinti visas<br />
pabaigos pozicijas tam tikru svoriu. Pavyzdžiui, šachmatuose<br />
visas pozicijas, kuriose laimi ba<strong>lt</strong>osios figūros, įvertiname 1,<br />
juodųjų figūrų laimėtas pozicijas vertiname (-1), o pozicijas, kai<br />
žaidimas baigėsi lygiosiomis, įvertiname 0.<br />
3. Lošėjai siekia priešingų tikslų: vienas nori, kad galutinės<br />
žaidimo pozicijos svoris būtų didžiausias, o antrasis stengiasi<br />
pasiekti mažiausio svorio baigiamąją poziciją.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Variantų perrinkimo algortimas su grįžimu atgal<br />
Apskaičiuojame optimalų rezu<strong>lt</strong>atą, kurį lošėjas gali pasiekti iš duotosios pozicijos<br />
A. Parametras tikslas (lygus MAX arba MIN) apibrėžia lošėjo strategiją.<br />
float Lošimas (pozicija A, int tikslas)<br />
begin<br />
(1) if ( A == pabaigosPozicija ) then<br />
(2) return Vertė(A);<br />
(3) else<br />
(4) if ( tikslas == MAX ) then<br />
(5) v = - ∞;<br />
(6) for all ( B ∈ Vaikai(A) ) do<br />
(7) v = max ( v, Lošimas (B, MIN) );<br />
end do<br />
(8) else<br />
(9) v = ∞;<br />
(10) for all ( B ∈ Vaikai(A) ) do<br />
(11) v = min ( v, Lošimas (B, MAX) );<br />
end do<br />
end if<br />
(12) return v;<br />
end if<br />
end Lošimas<br />
doc. dr. Vadimas Starikovičius Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Pavyzdys: lošimo uždavinio sprendimas su variantų<br />
perrinkimo algoritmu su grįžimu atgal<br />
Pradėkite nuo viršaus ir gaukite visų viršūnių svorius.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Šakų ir rėžių metodas taikymas lošimų uždaviniams<br />
Nagrinėjamų variantų skaičių galime sumažinti taikydami šakų<br />
ir rėžių metodą. Pritaikę jį lošimų algoritmams, gauname taip<br />
vadinama α–β metodą.<br />
Šio metodo idėja: vertindami viršūnės svorį, jį lyginame ir su<br />
viršūnės tėvo naujausiu įverčiu.<br />
Tarkime, kad viršūnės v tikslas yra MAX, o jos tėvo viršūnės w<br />
(jos strategija MIN) įvertis lygus α. Jeigu, tikrindami v vaikus,<br />
radome variantą, kurio svoris β ≥ α, tai nutraukiame tolesnę<br />
viršūnės v vaikų analizę, nes v pomedyje negali egzistuoti<br />
viršūnės w optimali žaidimo strategija. Taigi lošėjas, patekęs į<br />
w poziciją, niekada nesirinks ėjimo, vedančio į viršūnę v.<br />
Panašiai, jei viršūnės v tikslas yra MIN, tai jos vaikų analizę<br />
nutraukiame, jei radome variantą, kurio svoris β ≤ α.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
pav. : Lošimo uždavinio sprendimas α–β metodu. Pilka spalva<br />
pažymėtos tos medžio šakos ir viršūnės, kurių nereikia tikrinti<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
α–β algoritmas<br />
float αβ (pozicija A, int tikslas, double a)<br />
begin<br />
(1) if ( A == pabaigosPozicija ) then<br />
(2) return Vertė(A);<br />
else<br />
(3) B = KitasVaikas(A);<br />
(4) if ( tikslas == MAX ) then<br />
(5) v = - ∞; (6) while (v < a) && (B ≠ ∅) do<br />
(7) v = max (v, αβ (B, MIN, v) );<br />
(8) B = KitasVaikas(A);<br />
end do<br />
else<br />
(9) v = ∞; (10) while (v > a) && (B ≠ ∅) do<br />
(11) v = min (v, αβ (B, MAX, v) );<br />
(12) B = KitasVaikas(A);<br />
end do<br />
end if<br />
(13) return v;<br />
end if<br />
end<br />
αβ<br />
doc. dr. Vadimas Starikovičius<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Dinaminio programavimo metodas<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Viso variantų perrinkimo algoritmai dažnai neefektyvūs dėl<br />
labai didelio nagrinėjamų variantų skaičiaus.<br />
Analizuodami daugelį tokių algoritmų matome, kad<br />
skaičiuojant daug kartų sprendžiame tas pačias užduotis.<br />
Šio trūkumo neturi dinaminio programavimo metodas, kurį<br />
pasiūlė Belmanas (R. Bellman).<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Dinaminio programavimo metodo sąlygos<br />
Dinaminio programavimo metodas taikytinas tada, kai<br />
tenkinamos tokios sąlygos:<br />
1 Algoritmo vykdymo metu generuojamos užduočių aibės<br />
esmingai persidengia, todėl daug kartų sprendžiame tas<br />
pačias užduotis. Dinaminio programavimo metode<br />
įsimename jau spręstų užduočių sprendinius ir sprendžiame<br />
tik naujus uždavinius.<br />
2 Uždavinys tenkina Belmano sąlygą, kad optimalus<br />
sprendinys yra sudarytas iš atskirų mažesnių užduočių<br />
optimalių sprendinių. Šią sąlygą užrašome rekurentinės<br />
lygybės forma, ji smarkiai sumažina nagrinėjamų variantų<br />
skaičių.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Dinaminio programavimo metodo eiga<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Skaldyk ir valdyk algoritme užduotys generuojamos iš<br />
viršaus į apačią, t. y. pradinis uždavinys skaidomas į kelias<br />
mažesnes užduotis, kurios toliau dalijamos į mažesnes.<br />
Dinaminio programavimo metode uždavinį pradedame<br />
spręsti nuo mažiausių ir lengvai išsprendžiamų užduočių, jų<br />
rezu<strong>lt</strong>atus išsaugome (jei reikia) ir naudojame spręsdami<br />
didesnes užduotis. Taip surandame viso uždavinio<br />
sprendinį.<br />
Realizuodami dinaminio programavimo metodą<br />
nagrinėjame tik tuos variantus, kurių gali prireikti<br />
optimaliai strategijai sudaryti. Taip sataupome laiką, bet<br />
atsiranda papildomos atminties sąnaudos.<br />
Tokios strategijos pranašumus jau matėme nagrinėdami kai<br />
kuriuos rekursinius algoritmus, pvz., Fibonačio skaičius.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Dinaminio programavimo metodo taikymo pavyzdys<br />
Pateiksime dar vieną panašų pavyzdį, kai ieškome, kiek yra<br />
skirtingų būdų išrinkti k daiktų iš n daiktų aibės.<br />
Atsakymą apibrėžia derinių kombinatorinė formulė<br />
C k n = n!<br />
k!(n−k)! ,<br />
tačiau ji netinka dideliems n, nes faktorialas - labai greitai<br />
didėjanti funkcija. Pvz., 13! = 6.227.020.800 > 2 32 =<br />
4.294.967.296, t.y. naudojant unsigned integer 32-bitų duomenų<br />
tipą negalime išreikšti n!, kai n ≥ 13.<br />
Tačiau šio duomenų tipo kintamajame galima išsaugoti C k n iki<br />
n = 34: C 17<br />
34 = 2.333.606.220.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Rekursyvus C k n skaičiavimo algoritmas<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Cn k apskaičiavimui galime naudoti rekursinę lygybę:<br />
⎧<br />
1, k = 0,<br />
⎪⎨<br />
Cn k = Cn−1 k−1 + C n−1 k , 0 < k < n,<br />
⎪⎩<br />
1, k = n,<br />
kurios teisingumą patikriname atlikę elementarius veiksmus.<br />
int BinKoef (int n, int k)<br />
begin<br />
(1) if ( k == 0 || n == k ) then<br />
(2) return (1);<br />
(3) else<br />
(4) return ( BinKoef(n-1, k-1) + BinKoef(n-1, k) );<br />
end if<br />
end BinKoef<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Įvertinsime tokio algoritmo sudėtingumo funkciją T(n). Tegul,<br />
skaičiuodami binominį koeficientą Cn k , atliekame P(n, k)<br />
aritmetinių veiksmų. Tada T(n) = max 0≤k≤n P(n, k).<br />
Iš pateiktojo algoritmo gauname tokius sąryšius:<br />
⎧<br />
1, k = 0,<br />
⎪⎨<br />
P(n, k) = P(n − 1, k) + P(n − 1, k − 1), 0 < k < n,<br />
⎪⎩<br />
1, k = n,<br />
todėl P(n, k) = C k n . Jos reikšmė didžiausia, kai k = n/2. Taigi<br />
rekursinio algoritmo sudėtingumo funkcija<br />
T(n) = C n/2<br />
n =<br />
n!<br />
( (n/2)!<br />
) 2<br />
.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Pasinaudoję Stirlingo formule, gauname, kad<br />
n! = √ ( n ) n ( ) √ ( n ) n/2 ( )<br />
2πn 1+O(1/n) , (n/2)! = πn 1+O(1/n) ,<br />
e<br />
2e<br />
todėl teisingas asimptotinis įvertis T(n) = Θ(2 n / √ n).<br />
Matome, kad algoritmo veiksmų skaičius didėja eksponentiniu<br />
greičiu, taigi rekursyvus algoritmas yra paprastas, bet labai<br />
neefektyvus. Lentelėje pateikti skaičiavimo eksperimento<br />
rezu<strong>lt</strong>atai: T n yra binominio koeficiento Cn<br />
n/2 skaičiavimo<br />
laikas, ρ n =<br />
Tn<br />
T n−1<br />
.<br />
n T n ρ n<br />
32 18,5 2,015<br />
33 35,5 1,919<br />
34 71,3 2,008<br />
35 138 1,935<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Dabar pateiksime algoritmą, kurį gauname dinaminio<br />
programavimo metodu. Ir šis algoritmas naudoja rekursinę<br />
formulę:<br />
C k n = C k−1<br />
n−1 + C k n−1,<br />
kuri ir yra binominio koeficiento Belmano sąlyga.<br />
Skaičiuoti pradedame nuo mažiausio koeficiento C0 0 ir didiname<br />
parametro n reikšmę. Pagalbinių koeficientų reikšmes saugome<br />
matricoje H , turinčioje (n + 1) eilutę ir (k + 1) stulpelį.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Dinaminio programavimo binominių koeficientų<br />
algoritmas<br />
int BinKoef2 (int n, int k)<br />
begin<br />
(1) for ( i=0; i
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Dinaminio programavimo algoritmo sudėtingumas<br />
Naujuoju algoritmu binominį koeficientą apskaičiuojame, atlikę<br />
(n − k)(k + 1) + (k+2)(k+1)<br />
2<br />
veiksmų.<br />
Šis skaičius didžiausias, kai k = n 2<br />
(prisiminkite lygybę<br />
Cn k = Cn n−k ).<br />
Taigi dinaminio programavimo algoritmo sudėtingumo funkcija<br />
yra kvadratinė T(n) = 3n 2 /8 + O(n).<br />
Kokios yra dinaminio programavimo algoritmo atminties<br />
sąnaudos? Ar galima jas sumažinti?<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Euristiniai algoritmai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Daugeliui uždavinių variantų perrinkimo algoritmų<br />
sudėtingumas aprašomas nepolinomine (pvz., eksponentine)<br />
funkcija. Todėl dažnai visus variantus perrinkti neįmanoma net<br />
ir su šiuolaikiniais superkompiuteriais.<br />
Kai nėra žinomas pakankamai greitas algoritmas, randantis<br />
tikslųjį (optimalųjį) uždavinio sprendinį, naudojami algoritmai,<br />
gaunami atsisakius sprendinio tikslumo reikalavimo.<br />
Algoritmas vadinamas euristiniu arba tiesiog euristika (angl.<br />
heuristic), jei jis pakankamai greitai randa priimtiną, bet<br />
nebūtinai tikslųjį (optimalųjį) uždavinio sprendinį.<br />
Euristikos dažniausiai būna polinominio sudėtingumo. Tai<br />
pasiekiama patikrinant ne visus, o tik perspektyviuosius<br />
(euristikos apibrėžimo prasme) variantus.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Taip sudarytas algoritmas laikomas euristiniu, net jei jis<br />
praktiškai grąžina tiksliuosius sprendinius, bet nėra<br />
formalaus įrodymo, kad taip bus visada (t.y. bet kokiems<br />
uždavinio duomenims).<br />
Pavyzdžiui, sprendžiant paieškos ar optimizacijos<br />
uždavinius, populiarūs algoritmai gaunami naudojant<br />
godžiąją (angl. greedy) strategiją.<br />
Daugeliui uždavinių gaunami pagal šią strategiją taip<br />
vadinami godieji algoritmai yra tik euristikos, t.y.<br />
bendruoju atveju negarantuoja tikslaus (optimalaus)<br />
sprendinio radimo.<br />
Tačiau egzistuoja svarbus taikomieji uždaviniai, kurių<br />
sprendimui sukurti godieji algoritmai yra tikslieji<br />
algoritmai, t.y. jie randa tiksliuosius atitinkamų uždavinių<br />
sprendinius ir tai yra formaliai įrodyta.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Godžiųjų algoritmų sudarymo bendroji schema<br />
Uždavinio sprendinio paiešką išskaidome į n žingsnių.<br />
Kiekvienu žingsniu renkamės iš nedidelio baigtinio<br />
skaičiaus variantų m.<br />
Godieji algoritmai (angl. greedy) gaunami renkantis<br />
lokaliai geriausią variantą duotojo žingsnio metu (t.y.<br />
tą iš m, kuris šiuo žingsniu atneša didžiausią pelną).<br />
Aišku, kad tokia lokali pasirinkimo strategija nebūtinai<br />
yra optimali viso uždavinio sprendimo atžvilgiu. Bet jos<br />
realizavimo sąnaudos yra labai mažos: lokalaus pasirinkimo<br />
sudėtingumas – O(m), o viso godžiojo algoritmo<br />
sudėtingumas – tik O(nm) veiksmų.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Diskretusis kuprinės užpildymo uždavinys<br />
(angl. 0 − 1 knapsack problem)<br />
Tarkime, kad turime n daiktų, kurių tūriai yra v 1 , v 2 , . . . , v n , o<br />
kaina p 1 , p 2 , . . . , p n . Reikia rasti tokį daiktų rinkinį, kuris tilptų<br />
į V tūrio kuprinę, o daiktų vertė būtų didžiausia.<br />
Sprendžiame optimizavimo uždavinį:<br />
max (x 1p 1 + x 2 p 2 + . . . + x n p n ),<br />
(x 1 ,...,x n)∈D<br />
D = {x 1 v 1 + x 2 v 2 + . . . + x n v n ≤ V , x j ∈ {0, 1}}.<br />
Tiesioginio pilno perrinkimo algoritmo (angl. brute-force<br />
search) sudėtingumas - O(2 n ).<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Diskretusis kuprinės uždavinys. Godieji algoritmai.<br />
Pirmiausia pagal bendrąją godžiųjų algoritmų sudarymo<br />
schemą išskaidome sprendinio paiešką į n žingsnių:<br />
kiekviename žingsnyje dedame į kuprinę po vieną daiktą<br />
(jis ten ir lieka iki algoritmo pabaigos).<br />
Tada i-ame žingsnyje turime rinktis iš tų likusių n − i<br />
daiktų, kurie telpa į dar neužpildytą kuprinės tūrį.<br />
Lokaliai geriausio varianto (t.y. daikto) pasirinkimą galima<br />
apibrėžti 3 būdais:<br />
1 pagal mažiausią tūrį - v j ,<br />
2 pagal didžiausią kainą - p j ,<br />
3 pagal didžiausią santykinę vertę - p j<br />
v j<br />
.<br />
Visi 3 būdai duoda leistinus sprendinius, tačiau nei vienas<br />
negarantuoja tikslaus (optimalaus) sprendinio. Kuris būdas<br />
duos geresnį sprendinį priklauso nuo uždavinio duomenų.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Panagrinėkime pavyzdį (kuprinės tūris V = 100):<br />
Godieji sprendiniai pagal Optimalus<br />
p i<br />
i v i p i kainą tūrį s. vertę sprendinys<br />
v i<br />
1 100 40 0.4 1 0 0 0<br />
2 50 35 0.7 0 0 1 1<br />
3 45 18 0.4 0 1 0 1<br />
4 20 4 0.2 0 1 1 0<br />
5 10 10 1.0 0 1 1 0<br />
6 5 2 0.4 0 1 1 1<br />
sprendinio tūris 100 80 85 100<br />
sprendinio vertė 40 34 51 55<br />
Taigi diskrečiajam kuprinės užpildymo uždaviniui sudaryti<br />
godieji algoritmai yra tik euristikos.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Sudarykite godaus algoritmo pseudo-kodą ir raskite jo<br />
sudėtingumą.<br />
Kaip kitaip galima rasti optimalų uždavinio sprendinį?<br />
Tegu A(n, V ) yra maksimali vertė daiktų, išrinktų iš n, tokių,<br />
kad jų bendras tūris neviršija V . Tada A(n, V ) gali būti rastas<br />
pagal rekursinį sąryšį:<br />
⎧<br />
0, jei n = 0,<br />
⎪⎨ 0, jei V = 0,<br />
A(n, V ) =<br />
A(n − 1, V ), jei v n > V ,<br />
⎪⎩<br />
max {A(n − 1, V ), p n + A(n − 1, V − v n )} , jei v n ≤ V .<br />
Sudarykite dinaminio programavimo metodo algoritmą ir<br />
įvertinkite jo sudėtingumą.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Tolydusis (angl. fractional) kuprinės uždavinys<br />
Užduoties sąlyga tokia pati, kaip diskrečiajame uždavinyje,<br />
tik dabar daiktai yra dalūs ir galime imti jų dalį, t.y.<br />
0 ≤ x i ≤ 1, i = 1, 2, ..., n.<br />
Pavyzdžiui, tai gali būti aukso plytelės (diskretusis užd.) ir<br />
aukso smėlis (tolydusis), supakuotas ir birusis cukrus.<br />
Tada naudojame tokį godųjį algoritmą: surūšiuojame<br />
daiktus pagal jų santykines vertes ir kiekviename žingsnyje<br />
imame į kuprinę patį vertingiausią likusį daiktą (visą arba<br />
dalį, kiek telpa).<br />
Nagrinėkime daiktų rinkinį, pateiktą ankstesniame pavyzdyje.<br />
Tada į kuprinę nuosekliai įdedame visą 5-ą daiktą (jo tūris – 10,<br />
o vertė – 10), visą 2-ą daiktą (jo tūris – 50, vertė – 35) ir 40<br />
tūrio vienetų 1-ojo daikto (tūris – 40, vertė – 40 ∗ 0.4). Taigi<br />
toks krovinys užpildo visą kuprinę, o jo vertė – 61.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Godžiųjų algoritmų optimalumas<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Kada godžiuoju algoritmu visada randame optimalųjį (tikslųjį)<br />
uždavinio sprendinį? Turi būti patenkintos dvi sąlygos:<br />
1. (angl. optimal substructure property). Optimalų sprendinį<br />
galime apskaičiuoti išskaidę uždavinį į mažesnių (tokių pačių)<br />
užduočių seką ir suradę optimalius jų sprendinius.<br />
Tai yra dinaminio programavimo metodo Belmano sąlyga. Ji yra<br />
būtina, bet jos nepakanka, kaip matėme diskrečiojo kuprinės<br />
uždavinio atveju, kai ši sąlyga patenkinta, bet godieji algoritmai yra<br />
tik euristikos.<br />
Godžiajame algoritme visada renkamės tik lokaliai vertingiausią<br />
sprendinį, o dinaminio programavimo metode įvertiname tokio<br />
pasirinkimo pasekmes visiems tolesniems variantams.<br />
2. (angl. greedy-choice property). Atliekant lokaliai geriausią<br />
(godųjį) pasirinkimą kiekviename žingsnyje išlieka galimybė<br />
gauti viso uždavinio optimalųjį sprendinį.<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
Teorema. Godžiuoju algoritmu randame optimalųjį tolydaus<br />
kuprinės užpildymo uždavinio sprendinį.<br />
Įrodymas. Jei į kuprinę telpa tik vertingiausias daiktas ar jo<br />
<strong>dalis</strong>, tai godžiojo algoritmo optimalumas yra akivaizdus.<br />
Nagrinėkime atvejį, kai v 1 < V . Tada godžiuoju algoritmu<br />
pirmajame žingsnyje pasirinkome visą kiekį santykinai<br />
vertingiausio daikto - v 1 .<br />
Tarkime, kad egzistuoja optimalus rinkinys, kuriame šio<br />
produkto yra mažiau: w 1 < v 1 . Pažymėkime optimalaus<br />
rinkinio vertę P O .<br />
Tada, išėmę iš optimaliai užpildytos kuprinės (v 1 − w 1 )<br />
mažiausiai vertingo k-ojo produkto (k ≠ 1) ir įdėję tokį patį<br />
kiekį pirmojo produkto, gausime naują rinkinį, kurio vertė lygi<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai
Algoritmų sudarymo principai ir metodai<br />
Variantų perrinkimas ir rekursijos metodas<br />
Skaldyk ir valdyk metodas<br />
Šakų ir rėžių metodas<br />
Dinaminio programavimo metodas<br />
Euristikos ir godieji algorimai<br />
a) P O + (v 1 − w 1 )(s 1 − s k ) > P O , jei s 1 > s k (s i = p i<br />
v i<br />
), t.y.<br />
didesnė negu optimalaus rinkinio! Gavome prieštaravimą!<br />
b) P O , jei s 1 = s k , t.y. gavome kitą optimalų rinkinį (jų gali<br />
būti ne vienas, kai dalies produktų santykinės vertės sutampa),<br />
kuriame yra w 1 + (v 1 − w 1 ) = v 1 pirmojo produkto.<br />
Taigi godžiosios strategijos taikymas pirmajame žingsnyje (v 1<br />
įdėjimas) leidžia rasti optimalų rinkinį.<br />
Po pirmojo žingsnio vėl gavome kuprinės užpildymo<br />
vertingiausiais produktais uždavinį, tik sumažėjo kuprinės tūris<br />
(V − v 1 ) ir liko trumpesnis daiktų sąrašas. Remdamiesi<br />
matematinės indukcijos metodu, tvirtiname, kad godžiuoju<br />
algoritmu randame optimalų sprendinį. ✷<br />
doc. dr. Vadimas Starikovičius<br />
Algoritmų analizės specialieji skyriai