Ovdje

Algoritmi i logička struktura programa
Sadržaj
UVOD ............................................................................................................................................... 3
ALGORITMI U RAČUNALNOJ ZNANOSTI ................................................................................ 4
PRIKAZ ALGORITAMA ..................................................................................................................................... 5
STRUKTURA ALGORITMA ............................................................................................................................. 6
STRUKTURA PROGRAMA .............................................................................................................................. 9
ANALIZA ALGORITAMA........................................................................................................... 10
VREMENSKA SLOŽENOST .......................................................................................................................... 10
PROSTORNA SLOŽENOST ........................................................................................................................... 17
VRSTE ALGORITAMA ............................................................................................................... 18
PODIJELI PA VLADAJ ..................................................................................................................................... 18
DINAMIČKO PROGRAMIRANJE ................................................................................................................ 23
POHELPNI PRISTUP ...................................................................................................................................... 30
BACKTRACKING .............................................................................................................................................. 34
ALGORITMI SORTIRANJA ....................................................................................................... 38
SELECTION SORT............................................................................................................................................ 39
INESERTION SORT ......................................................................................................................................... 39
BUBBLE SORT................................................................................................................................................... 40
QUICK SORT....................................................................................................................................................... 40
ZAKLJUČAK................................................................................................................................. 43
LITERATURA .............................................................................................................................. 44
2
Algoritmi i logička struktura programa
UVOD
Priču o algoritmima možemo započeti kao i svaku klasičnu priču. Jednom davno živio
je u Bagdadu pisac, matematičar, astronom i geograf po imenu Muhammed ibn Musa al
Khowarizmi. Vjerojatno nije ni sanjao, dok je daleke 852. godine pisao knjigu Kitab al
jabar w'al-muqubala, da će od toga nastati čak dva uzroka glavobolje Ďacima i studentima
deset, jedanaest stoljeća nakon toga. Njegov al jabar je postala algebra, a od njegovog
prezimena al Khowarizmi je nastao naziv algoritmi. On je u svojoj knjizi prikazao rješenja
nekih aritmetičkih problema u obliku uputstava koja su se sastojala od točno odreĎenih
pravila. Upravo su ta uputsva (algoritmi) danas postala važno i samostalno područje računalne
znanosti.
Ali što je zapravo algoritam?
U računalnoj obradi podataka, algoritam je skup postupaka (preciznih uputa) koje
treba učiniti da bi se riješio odreĎeni zadatak. To su zapravo, toliko precizne upute da za
njihovo rješavanje nije potrebna inteligencija, odnosno dat problem moramo svesti na manje
potprobleme koje je trivijalno riješiti. I upravo taj način razmišljanja, koji programeru
omogućuje da pravilno postavi složeni problem, te ga raščlani na manje potprobleme, čini od
njega umjetnika baš kao i glazbenika ili slikara.
Algoritmi su svuda oko nas. Naučeni postupak množenja, recept u kuharici, upute za
uporabu, proces spajanja gena, sve su to algoritmi koji nas okružuju i s kojima se
svakodnevno susrećemo u svim granama ljudske znanosti.
Upravo zbog tolike zastupljenosti i proširenosti algoritama u ovom ću seminaru
obraditi, ne bazirajući se na programski jezik, već samo na teorijski dio, neke od
najosnovnijih algoritama računalne znanosti.
3
Algoritmi i logička struktura programa
ALGORITMI U RAČUNALNOJ ZNANOSTI
Algoritam je, u općem slučaju, konačni red operatora, elementarnih obrada i pravila o
njihovoj primjeni u cilju dobivanja rješenja nekog problema. IzvoĎenje svakog operatora
predstavlja jedan algoritamski korak.
Nažalost, sa računalnog gledišta ova definicija nije dovoljna pa se mora nadopuniti još
nekim uvjetima koje algoritam mora zadovoljiti. To su:
1) Definiranost
2) Konačnost
3) Rezultat
Pod pojmom definiranost smatramo da svaka operacija ili pravilo mora imati
definirano samo jedno značenje, tj. rezultat jedne operacije je jednoznačno definiran.
Svaki korak algoritma, mora biti takav da bi ga, u principu, mogao izvesti čovjek
koristeći papir i olovku, za konačno vrijeme. Odnosno, algoritam se mora zaustaviti u
konačnom vremenu nakon konačnog broja koraka, a vrijeme izvršavanja algoritma mora biti
razumno kratko.
Po završetku rada algoritma mora postojati mogućnost da se ustanovi je li algoritam
postigao svoji cilj ili nije. Odnosno, je li došao do nekog rezultata.
4
Algoritmi i logička struktura programa
PRIKAZ ALGORITAMA
Postoje različite mogućnosti prikazivanja algoritma, no najčešće se koristi grafički
prikaz pod imenom dijagram tijeka programa („flowchart“). Dijagramom tijeka, svaka je
akcija prikazana točno odreĎenim grafičkim simbolom čime se osigurava jednostavnost i
jednoznačnost algoritma.
GRAFIČKI SIMBOL:
ZNAČENJE:
TERMINATOR
UNOŠENJE PODATAKA
IZDAVANJE PODATAKA
OBRADA PODATAKA
ODLUKA
POVEZIVANJE ALGORITAMSKIH
KORAKA
5
Algoritmi i logička struktura programa
STRUKTURA ALGORITMA
Pod sturkturom algoritma smatramo redoslijed izvršavanja algoritamskih koraka.
Razlikujemo 3 osnovne algoritamske stukture:
1) LINIJSKA
2) RAZGRANATA
3) CIKLIČKA
LINIJSKA STRUKTURA
Kod linijske strukture algoritamski koraci se izvršavaju jedan za drugim redoslijedom
kojim su napisani.
Algoritam za zamjenu kotača na automobilu.
Početak
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
Pripremi dizalicu
Pripremi rezervni kotač
Olabavi vijke
Podigni auto
Odvrni vijke
Skini kotač
Stavi rezervni kotač
Zavrni vijke
Spusti auto
Zategni vijke
Spremi dizalicu
Spremi kotač
Kraj
6
Algoritmi i logička struktura programa
RAZGRANATA STRUKTURA
Razgranata struktura je struktura u kojoj tok zavisi o ispunjenosti nekog uvjeta.
Početak
1. Stani ispred semafora
2. Pogledaj semafor
ZELENO
NE
DA
Prijeđi cestu
Čekaj zeleno i
prijeđi cestu
Kraj
Stajemo ispred semfaora, nakon toga gledamo je li uvjet ispunjen, odnosno svijetli li
zeleno svjetlo na semaforu. Ukoliko svijetli, prelazimo cestu, u suprotnom čekamo zeleno
svjetlo i tek onda prelazimo cestu.
7
Algoritmi i logička struktura programa
CIKLIČKA STRUKTURA
U cikličkoj strukturi postoji odreĎen broj koraka koji se ponavlja više puta. Ako je
broj ponavljanja poznat struktura je konstantna (tzv. brojčani ciklus), a ako broj ponavljanja
nije poznat već zavisi o ispunjenosti nekog uvjeta, struktura je promjenjiva (tzv. uvjetni
ciklus)
Brojčani ciklus:
Uvjetni ciklus
Napuni 10 boca vodom.
Prijelaz preko ulice bez semafora
Početak
Početak
Otvori vodu
Stani ispred kolnika
Ponavljaj
10 puta
Pogledaj lijevo i desno
NE
Uzmi praznu bocu
Nema
vozila
DA
Napuni je vodom
Sačekaj malo
Zatvori bocu
Prijeđi ulicu
Odloži punu bocu
Kraj
Zatvori vodu
Početak
8
Algoritmi i logička struktura programa
STRUKTURA PROGRAMA
Svaki se program sastoji od naredbi koje se formiraju koristeći riječnik iz riječnika
odreĎenog programskog jezika i naziva koje programer dodjeljuje memorijskim lokacijama.
U te memorijske lokacije uskladišteni su podaci s kojima se radi. Pišući program moramo se
držati odreĎenih pravila, odnosno sintakse.
Tako npr. svaka naredba završava sa oznakom za kraj naredbe. Najčešće je to točka
zarez (;).
Naredbe se izvršavaju redosljedom kojim su napisane, ukoliko taj redoslijed nije
izmjenjen posebnim naredbama za izmjenu toka programa.
Naredbe se mogu podijeliti u dvije kategorije. Izvršne naredbe, odnosno one koje se u
procesu prevoĎenja programa prevode u odgovarajući strojni jezik i neizvršne- one kojima se
daju upute prevoditelju neophodne za prevoĎenje programa (npr. definiranje imena
memorijskih lokacija, definiranje tipova podataka itd.). S obzirom na to da su namjenjene
prevoditelju, one se koriste samo za prevoĎenje i ne prevode se u strojni jezik.
U većini programskih jezika, u programu se na početku pravi odjeljak za neizvršne
naredbe, a poslije toga slijedi blok sa izvršnim naredbama. Tako se prevoditelj prvo upoznaje
s napucima za prevoĎenje programa a tek onda slijedeći te naputke i pravila, učitava izvršne
naredbe i prevodi ih u strojni jezik.
U svim programskim jezicima znakovi za formiranje elemenata su alfabetski znakovi
(velika i mala slova engleske abecede), numerički (znamenke od 0 do 9) i specijalni (+, -,
=,...). Alfabetski i numerički znakovi zajedno se nazivaju alfa-numerički.
9
Algoritmi i logička struktura programa
ANALIZA ALGORITAMA
Analiza algoritama je iznimno važna u dizajniranju i programiranju algoritama. Često
postoji više načina koji vode do istog rješenja. Mi moramo odabrati onaj najefikasniji.
U odreĎivanju efikasnosti algoritma, najčešće gledamo vremensku i prostornu
složenost.
Vremenska skoženost je vrijeme potrebno za izvoĎenje odreĎenog algoritma. Ne
mjeri se u sekundama kao što bi bilo logično, već se mjeri u nekim osnovnim mjernim
jedinicama kao što su strojne instrukcije, aritmetičke operacije itd.
Brzina se odreĎuje usporeĎivanjem algoritama, a ne usporeĎivanjem računala ili
arihitekture računala.
Prostorna složenost je memorija potrebna za izvoĎenje algoritma. Jedinica mjere
može biti bit, bajt, riječ, cijeli broj, itd. Prostorna složenost je manje ograničavajuća jer
algoritam istu memorijsku lokaciju može koristiti više puta tijekom izvoĎenja.
VREMENSKA SLOŽENOST
Različite vremenske složenosti najjednostavnije ćemo prikazati na primjeru.
Izvrednjavanje polinoma
Zadan je niz realnih brojeva an , an 1 , ..., a0 i realni broj x. Izračunajte vrijednost
polinoma:
Pn ( x) an xn an 1xn
1
an 2 xn
2
... a1x a0
Rješenje 1)
Pristupimo problemu preko indukcije. Svodimo rješavanje zadanog problema na
rješavanje manjeg problema. Pokušajmo ukloniti videći koeficijent an . Pretpostavimo da
znamo izračunati Pn 1 ( x) an 1xn
1
an 2 xn
2
... a1x a0 .
Baza indukcije je a0 . Sada
rješavamo problem pomoću rješenja manjeg problema ( Pn 1 ( x) ). Korak indukcije je:
Pn ( x) an xn
10
Pn 1 ( x) .
Algoritmi i logička struktura programa
Ovaj algoritam očito daje točno rješenje, meĎutim nije efikasan. Izvršenje zahtijeva
n (n 1) (n 2) ... 1
n(n 1)
množenja i n zbrajanja.
2
Rješenje 2)
Bolje rješenje dobivamo ako uzmemo jaču pretpostavku indukcije: Znamo riješiti
Pn 1 ( x) i znamo izračunati x n 1 . Sada u koraku indukcije x n dobijemo iz x n
1
uz jedno
množenje, a zatim an x n uz još jedno množenje. Pn ( x) zahtjeva još jedno množenje i
zbrajanje. Ukupno imamo 2n množenja i n zbrajanja. Iako smo u koraku indukcije zahtijevali
više, ukupan broj operacija je znatno manji. Ovaj algoritam je jednostavan, efikasan i naoko
optimalan, no postoji i bolji algoritam.
Rjesenje 3)
Poukušajmo ukloniti prvi koeficijent a0 . Zapišimo:
Pn ( x) (an xn
1
an 1xn
2
... a1 ) x a0
Pn' ( x) x a0 .
Pretpostavka indukcije: znamo izračunati Pn' ( x) . Iz njega, jednim množenjem i jednim
zbrajanjem dobijemo Pn ( x) . Ako polinom raspišemo do kraja dobijemo:
Pn ( x) ((...((an x an 1 ) x an 2 ) x an 3 ) x ...) x a1 ) x a0 .
Ovaj postupak izvrednjavanja polinoma zovemo Hornerovo pravilo. Vidimo da za cijeli
postupak koristimo samo n množenja i n zbrajanja, te jednu doadtnu memorijsku lokaciju.
11
Algoritmi i logička struktura programa
BIG OH NOTATION
Kao što smo već rekli, u suvremenom računarstvu vrlo važnu ulogi ima odreĎivanje
složenosti algoritma. Složenost algoritma iskazuje se asimptotskim ponašanjem niza ( an )
koji predstavlja gornju granicu za broj računskih operacija (ili broj usporeĎivanja) dovoljnih
da bi se algoritam realizirao.
Kompleksnost algoritma definira se na različite načine. Ovisno o problemu, najčešće
želimo izrazti složenost u ovisnosti od ulaznih podataka.
Npr. Euklidov algoritam za pronalaženje najveće zajedničke mjere ovisi o brojevima a
i b. Gaussov algoritam za rješavanje linearnog sustava n jednaĎba s n nepoznanica ovisi o
ulaznom broju n.
Jasno je da an definiran sa an
1 2
n raste brže od niza bn
100
veliki n, jer kvadratna funkcija raste brže od linearne, ili točnije lim
x
1000n za dovoljno
bn
= 0.
an
Stoga, kažemo da niz ( an ) asimptotski dominira niz (bn ) ako postoje konstante n0 i
M>0 takve da je:
(bn )
M ( an ) , za sve n
n0 .
Označimo sa O(an ) skup svih nizova (bn ) koji su asimptotski dominirani slijedom
( an ) . Skup O(an ) zovemo veliki O od ( an ) i pišemo:
bn
O(an )
(an ) asimptotski dominira (bn ) .
Svrha ove oznake je da naĎe što jednostavniji niz ( an ) koji dominira (bn ) i opisuje
brzinu rasta. Oznaka O nam omogućuje da asimptotsko ponašanje slijedova opišemo samo s
onim što je zaista najbitnije.
Primjer 1)
Ako vrijeme izvršavanja nekog algoritma raste po funkciji T (n)
4n 2 2n 2 za
dovoljno veliki n može se slobodno zanemariti član 2n zbog toga što će član 4n 2 biti toliko
velik da iako zanemarimo 2n neće biti bitnijih promjena u rezultatu.
12
Algoritmi i logička struktura programa
Na
sličan
način
možemo
zanemariti
i
konstante.
Ukoliko
T (n) 100, 000, 000n2 , U (n) n3 će za n veći od 100,000,000 biti veći od n
imamo
k.
Primjer 2)
Na ovom grafu primjećujemo da funkcija g(n) asimptotski dominira funkciju f(n) jer
postoje takve konstante c i k da je za svaki broj n
k funkcija cg(n) > f(n).
Primjer 3)
f ( n)
Funkcija
n 2 3n 4 asimptotski je dominirana funkcijom g (n)
n2 , jer
ukoliko uzmemo konstantu M = 2 i n0 = 11 uočit ćemo da je 2 n 2 > n 2 3n 4 , n 11.
Ovaj primjer odlično prikazuje ono što definicija govori.
Sljedeća tablica prikazuje porast broja n u odreĎenim funkcijama:
N
log2N
N
N log2N
N2
N3
2N
N!
8
3
8
24
64
512
256
40300
16
4
16
36
256
4096
6.5×104
> 2×1013
64
6
64
384
4096
262144
1.84×1019
> 1089
Vrijedi spomenuti da 1012 s čini više od 20 000 godina. Broj 64! Je veći od 1080,
koliko iznosi procjena za broj atoma u vidljivom svemiru.
13
Algoritmi i logička struktura programa
Npr. složenost Cramerova algoritma za rješavanje linearnog sustava n jednadžaba s n
nepoznanica ima čak faktorijeličnu složenost (O(n!)), s druge strane, možemo isti problem
riješiti Gaussovim algoritmom koji ima kubnu složenost (O(n3)). Tako će npr. 20 jednadžaba
s 20 nepoznanica Gaussov algoritam riješiti za djelić sekunde, dok će Cramerovim pravilom
trebati nekoliko stotina tisuća godina.
Zašto je uopće važna brzina izvoĎenja algoritma?
Osim što bi svatko volio doživjeti rezultat algoritma možemo za primjer uzeti i
digitalnu kameru od 1 Mpx. Recimo da algoritam koji procesira sliku na ekran ima složenost
O(n2), ukoliko treba mikrosekunda za procesuirati jedan pixel obraĎivanje bi trajalo tjednima,
a za sliku od 3 Mpx i mjesecima.
U računalstvu se algoritam smatra dobrim ako mu je kompleksnost najviše
polinomijalnog rasta. Algoritmi s eskponencijalnom kompleksnošću, a pogotovo s
faktorijelnom smatraju se nepovoljni za primjenu.
SLOŽENOST POTENCIRANJA
Binarni prikaz prirodnog broja
Standardna zadaća svakog računala je pretvaranje prirodnih brojeva iz dekadskog
sustava u binarni sustav. Taj se prikaz dobiva uzastopnim djeljenjem sa 2.
Algoritam:
1) Učitaj n, stavi i = 1
2) Podijeli n sa 2, naĎi kvocijent q i ostatak r; spremi r kao ai
r
3) Ako je q = 0 zaustavi program
4) Stavi n = q
5) Stavi i = i + 1, prijeĎi na korak 2
Na kraju treba ispisati broj n pomoću bitova n
n a0 a1 2 ... ak 2k , pri čemu je ai
0,1 , ak
brojeva ai .
14
ak ak 1...a1a0 . Taj zapis shvaćamo kao
1 . Brojač i nam treba zbog ispisa
Algoritmi i logička struktura programa
Pogledajmo jednostavan primjer:
i
n
q
r
0
27
13
1 = a0
1
13
6
1 = a1
2
6
3
0 = a2
3
3
1
1 = a3
4
1
0
1 = a4
Prema tome je:
27 a0 a1 2 a2 22 a3 23 a4 24 1 2 23 24 ,
tj. 2710 = 110112.
Očito je da je broj operacija dijeljenja jednak broju binarnih znamenaka (bitova) broja
n. Odnosno, složenost ovog algoritma je samo logaritamska. Označimo sa h(n) broja
operacija, tada je h(n)
log 2 n
1 , dakle vrlo povoljna.
DOKAZ:
Neka je k najveći prirodan broj takav da je 2k
n
2k 1. Broj znamenki u binarnom
zapisu jednak je k+1, jer računamo svih k+1 potenciju baze 2 u binarnom obliku broja n, od
nulte do k-te: n a0 20 a1 21 ... ak 2k . Logaritmirajući ovu nejednakost po bazi 2
dobivamo k
log 2 n
k 1, dotično k = log 2 n . Dakle broj znamenki je jednak log 2 n +1.
Potenciranje prirodnim brojem n
Neka je zadan realni broj a > 0 i n N. Vrlo jednostavan algoritam za izračunavanje an
zasniva se na petlji „računaj članove slijeda xi = xi a, gdje je i = 1, 2, ...., n, x1=a. Dakako,
xn = an je dobiven nakon n-1 uzastopnih koraka pa je složenost jednak O(n). Zanimljivo je da
postoji algoritam koji ovaj problem riješava u bitno manje koraka, čak logaritamskom
složenošću.
Ideja je slijedeća. Pogledajmo najprije an gdje je n = 2k. Možemo pisati:
an
(...(a 2 ) 2 ...) 2 ,
15
Algoritmi i logička struktura programa
gdje se u eksponentu broj 2 pojavljuje k puta. Na temelju ovog identiteta vidimo da možemo
proračun a n programirati pomoću petlje koja sadrži samo k uzastopnih kvadrata. Kako je
n
2 k , složenost ovog algoritma je u ovom slučaju jednaka O(log2n), logaritamska.
Ovu je ideju moguće modificirati tako da se dobije jednostavan algoritam za
izračunavanje a n i to logaritamske složenosti za bilo koji n, ne nužno 2k.
Ilustrirajmo primjerom:
Uzmimo broj x a 27 , tj n = 27. Napišimo eksponent n u binarnom zapisu:
27 1 2 23
2 4 . Onda je x
a 27
4
3
a2 a2 a2 a
a16 a8 a 2 a .
Za a16 nam trebaju 4 uzastopna kvadrata broja a. MeĎutim njima su dobiveni i a 8 i a 2 .
Zatim imamo još 3 množenja, dakle ukupno samo 7 za razliku od 26 koja bismo imali u
prvom algoritmu potenciranja. Ideja je da se za algoritam brzog potenciranja iskoristi
algoritam za pretvaranje broja iz dekadske baze u binarnu. Uz male modifikacije tog
algoritma dobit ćemo algoritam za potenciranje u logaritamskom vremenu.
Tako dobiveni algoritam za brzo potenciranje glasi:
1) Učitaj a, n i stavi x = 1
2) Podijeli n sa 2, naĎi kvocijent q i ostatak r
3) Ako je r = 1 stavi x = x
a
4) Ako je q = 0 zaustavi program
5) Stavi n = q
6) Stavi a = a a i prijeĎi na korak 2
Pogledajmo što se dogaĎa ako je n = 27.
i
n
q
r
a
x
0
27
13
1
a
a
2
1
13
6
1
a
a3
2
6
3
0
a4
a3
3
3
1
1
a8
a11
4
1
0
1
a16
a27
16
Algoritmi i logička struktura programa
Analiza istog algoritma:
Algoritam nešto računa jedino u slijedeća tri koraka: korak broj 2 – dijeli, korak broj 3
– množi i korak broj 6 – množi. Broj operacija označimo sa h(n). To je mjera za složenost
dotičnog algoritma. Pri svakom prolazu kroz petlju provodi se dijeljenje u drugom koraku.
Taj broj je jednak
log 2 n +1. Prema tome, ukupan broj operacija je najviše
h(n) 3(log 2 n 1) , odnosno h(n) O(log 2 n) . Ovaj algoritam ne možemo više optimizirati.
PROSTORNA SLOŽENOST
Pod prostornom složenošću podrazumjevamo koliko prostora u memoriji zauzimaju
podaci koje odreĎeni algoritam generira. OdreĎuje se zbrajanjem veličine memorijskih
lokacija koje ti podaci zauzimaju.
Broj bitova u binarnom obliku broja n jednak je B = log 2 n +1. Ova nam relacija
omogućava
da
log 2 n
log 2 n
B
složenost
algoritma
izrazimo
kao
1 log 2 n 1 onda je B 1 log 2 n
2B
1
n
funkciju
od
B.
Kako
je
B , odnosno,
2B
Drugim riječima, ako broj svih bitova broja B raste linearno, onda n raste
eksponencijalno, kao 2B i obratno. Stoga je razumno memorijsku složenost definirati na
slijedeći način: m( B) h(2B ) , gdje je h ( n ) vremenska složenost.
Npr. Algoritam brzog potenciranja ima logaritamsku vremensku složenost stoga
pišemo:
m( B) h(2B ) 3(log2 n 1) 3( B 1) , odnosno, O(B),
dok za sporo potenciranje imamo:
h(n)=n –1 , tj. m( B)
h(2 B )
2 B 1 , O(2B ) ,
dakle eksponencijalna vremenska složenost.
17
Algoritmi i logička struktura programa
VRSTE ALGORITAMA
Iskustveno je pronaĎeno nekoliko općenitih strategija za oblikovanje algoritama.
Najvažnije su:
1) Podijeli pa vladaj (divide and conquer)
2) Dinamičko programiranje
3) Pohlepni pristup (Greedy)
4) Backtracking (Strategija odustajanja)
Generalno, svaki problem traži neki svoj pristup, ne možemo sve algoritme svrstati u
ove četiri kategorije, ali su se ove strategije pokazale uspješne za mnoge probleme, pa je to
razlog zašto se najviše koriste u rješavanju novih problema.
PODIJELI PA VLADAJ
Strategija podijeli pa vladaj jedna je od najprimjenjivijih strategija za oblikovanje
algoritama. Ideja je da se zadani problem „razbije“ u nekoliko manjih istovrsnih problema.
Tako da se rješenje polaznog problema može relativno lako konstruirati iz rješenja manjih
problema. Dobiveni algoritam je rekurzivan, jer se svaki od manjih problema i dalje
„razbija“ u manje probleme.
Nužna pretpostavka ove tehnike je da postoji neka relativno jednostavna tehnika
rješavanja dovoljno malog problema.
Kojom metodom rješavamo te „dovoljno male“ probleme?
Odgovor na to pitanje glavni je koncept podijeli pa vladaj metode. Uzmimo u obzir
slijedeće: imamo algoritam koji rješava neki problem veličine n u cn2 koraka. Dok drugi
algoritam isi problem rješava na slijedeći način. Podijeli ga na 3 manja potproblema i
iskombinira ta tri rješenja u dn koraka. Pretpostavimo da potprobleme rješavamo koristeći
prvi algoritam, znači u cn2 koraka.
Označimo sa:
T1 (n) - složenost prvog algoritma, a sa
T2 ( n) - složenost drugog algoritma
18
Algoritmi i logička struktura programa
Tada je
T1 (n) cn2 , dok je
T2 (n) 3T1 (n / 2) dn
3 2
(cn ) dn
4
Za male vrijednosti varijable n prvi algoritam će biti brži od durgog, no za velike
vrijednosti n-a drgui algoritam će biti efikasniji.
Množenje dugačkih cijelih brojeva
Klasičan algoritam množenje dva broja glasi:
Množi x sa svakom znamenkom y-a i zbrajaj djelomične rezultate. Taj algoritam
zahtijeva računanje n produkata veličine n, pa je složenost algoritma O(n2).
Strategija podijeli pa vladaj svodi se na slijedeći algoritam:
Svaki od brojeva x i y podijelimo na dva dijela duljine
n
bitova , zbog jednostavnosti
2
se uzima da je n potencija broja 2.
n
A
x
x
y
C
B
n
2
A 2x
D
n
x
I tada je produkt jednak:
AB 2
n
2
A 22
y
C 22
B
n
D
n
A 2x2 AB 2 2
x y
B
x
AC 2
B
n
( AD BC ) 2
n
2
BD
Ovim smo algoritmom jedno množenje velikih n-bitnih brojeva zamijenili s 4 množenja malih
n
bitnih brojeva, tri zbrajanja brojeva duljine najviše 2n bitov, te dva pomicanja bitova
2
n
n
2
(množenje s 2 i 2 ). Dalje, AC, AD, BC i BD množimo na sličan način kao i xy, pošto
zbrajanje i pomicanje bitova zahtijevaju O(n) koraka ukupna složenost je:
T (n) 4 T (n / 2)
O(n)
Kostanta 4 je zbog toga što imamo 4 množenja: AC, AD, BC, BD.
Izračunavanjem ove rekurzivne relacije ustanovili bismo da je složenost ovog
algoritma O(n2), dakle ista kao i kod običnog (školskog) množenja.
19
Algoritmi i logička struktura programa
Dakle ,strategija podijeli pa vladaj daje algoritam iste složenosti kao klasični
algoritam. Ali naravno, algoritam možemo poboljšati. Naime, matematičar C. F. Gauss
jednom je prilikom primijetio da umnožak dva kompleksna broja,
(a+bi)(c+di)=ac-bd+(bc+ad)i,
ima 4 množenja, ali da se u biti može svesti i na 3 množenja: ac, bd, (a+b)(c+d), jer je
bc+ad=(a+b)(c+d)-ac-bd.
Gledajući s Veliko O strane to i nije takva razlika no razlike se primijete ukoliko
primjenjujemo rekurziju. Tako složenost ovog programa izgleda ovako:
T ( n)
3T ( n / 2) O( n) .
Dakle, složenost je O(nlog2 3 ) , odnosno O (n1.59 ) .
20
Algoritmi i logička struktura programa
Primjer 1)
Problem je utvrditi postoji li u listi element sa zadanom vrijednošću.
Strategija podijeli pa vladaj dovodi nas do sljiedećeg algoritma:
1) Što je lista dulja, teže ju je pretražiti pa ju dijelimo u npr. 3 manje liste i u
svakoj se zasebno traži zadana vrijednost.
2) Tražena vrijednost se javlja u početnoj listi ako se javaj u bar jednoj manjoj
listi, znači konačno rješenje se dobije primjenom logičke operacije „ili“ na
djelomična riješenja.
Ako je u početku lista sortirana ovaj algoritam se može bitno pojednostaviti i to tako
da listu podijelimo na 3 manje pa će srednja lista imati samo jedan element, a preostale dvije
su jednake duljine. Jedna operacija usporeĎivanja nam omogućuje da se vrijednost odmah
pronaĎe ili da se odbace dvije liste. Taj algoritam naziva se binarno pretraživanje.
Recimo da tražimo broj 4 u listi: 1 3 3 4 6 6 7 8 9 9
Listu dijelimo na 3 dijela:
Lista: 1 3 3 4 6
6
7899
UsporeĎujemo 6 sa 4 ukoliko je 6 = 4 to je rješenje, inače ako je 6 > 4 gledamo lijevu listu
inače desnu.
Lista: 1 3 3 4 6
Opet dijelimo na 3 dijela.
Lista: 1 3
3
46
UsporeĎuejmo 4 sa 3. Uzimamo desnu podlistu.
Lista: 4 6
Lista: Nema lijeve
4
6
Rijesenje je 4.
Složenost ovog algoritam je Tmax (n) O(log n) . Jedna od varijacija podijeli pa vladaj
algoritama je „smanji pa vladaj“ metoda. Riječ je o podijeli pa vladaj algoritmu u kojemu
riješenje ne ovisi o svim podproblemima već samo o jednom. Primjer toga je binarno
pretraživanje, kao i pronalaženje najvećeg elemnta u listi.
21
Algoritmi i logička struktura programa
Primjer 2)
Problem je pronaći najveći elemnt u listi.
Algoritam radi na sličan način kao i prijašnji. Početnu listu podijelimo na 2 dijela.
PronaĎemo najveći element u lijevoj podlisti te ga usporedimo s najvećim elementom u
desnoj podlisti i ispišemo veći.
1
1
1
10
10
12
12
10
14
17
12
10
17
15
14
17
15
14
17
2
2
15
Dobili smo da je točno rješenje 17.
22
7
7
15
17
7
2
15
17
7
Algoritmi i logička struktura programa
DINAMIČKO PROGRAMIRANJE
Metoda „podijeli pa vladaj“ dovela nas je do mnogih zanimljivih rješenja. Dijelili smo
problem na manje probleme i spajali ih u konačni rezultat. U dinamičkom programiranju,
princip svodimo do krajnjih granica, kada neznamo točno koje potprobleme moramo riješiti,
pa ih riješimo sve, pohranimo ih, te ih koristimo za daljnje rješavanje većih problema.
U strategiji dinamičkog programiranja javljaju se dva glavna problema. Prvo; nekad
nije moguće spojiti dva manja potproblema u veći. Drugo; moguće je da postoji neprihvatljivo
veliki broj potproblema koje treba riješiti. Nekad, broj potproblema koje treba riješiti raste
eksponencijalno s veličinom zadanog problema, a rekurzijom se isti potproblemi rješavaju
više puta što dovodi do nepotrebnog gubljenja vremena. U takvim situacijama dinamičko
programiranje dobro doĎe.
Algoritmi tipa „podijeli pa vladaj“ idu od vrha prema dolje, a algoritmi dinamičkog
programiranja idu najčešće od dna prema gore. Prvo se rješavaju problemi manje veličine, pa
nešto veći, itd. Sve dok se ne dosegne potpuna veličina zadanog problema. Vrlo je važan
redoslijed ispunjavanja tablice. Strategija dinamičkog programiranja zahtijeva ponekad
rješavanje potproblema koji nisu potrebni za rješenje problema, no to je još uvijek isplativije
od rješavanja istih problema mnogo puta.
Računanje fibonaccijevih brojeva
Strategija podijeli pa vladaj daje rekurzivnu funkciju koja glasi:
F0
1 ; F1 1 ; Fn
Fn
1
Fn 2 , n > 1
Ako izračunamo složenost ovog algoritma, dobit ćemo da je ona jednaka O(1.618n);
dakle vrijeme izvršavanja raste eksponencijalno s veličinom ulaza. Strategija dinamičkog
programiranja dovodi nas do puno boljeg rješenja. Prvo se riješi trivijalan problem za F0 i F1 ,
iza njih se izračuna F2 , pa F3 iz F2 i F1 , itd. Time se prvo riješe jednostavniji problemi i
spreme se njihovi rezultati koji se dalje koriste za rješavanje malo složenijih problema, čiji se
rezultati takoĎer spremaju za daljnje rješavanje malo složenijih problema itd.
23
Algoritmi i logička struktura programa
Složenost ovog algoritma je O(n), dakle linearna, što je bitno brže od prvog algoritma.
Prostorna složenost ovog algoritma je minimalno povećana (samo za dvije cjelobrojne
varijable).
Problem određivanja šanse za pobjedu u nadmetanju
Problem je slijdeći. Dva natjecatelja A i B se nadmeću u nekoj sportskoj igri koja je
podijeljena u dijelove, setove, runde ili partije. U svakom dijelu igre točno jedan igrač bilježi
jedan bod. Igra traje sve dok jedan igrač ne osvoji ukupno n bodova. Pretpostavlja se da su
igrači podjednako jaki, tako da svaki ima 50% šanse da dobije bod u bilo kojem dijelu igre.
Označimo sa P(i, j) vjerojatnost da će A biti konačan pobjednik u situaciji kada A treba
i bodova do pobjede, a B treba još j bodova do pobjede. Npr. ako je n = 4, ako je A dobio 2
boda, a B dobio 1 bod, tada je i = 2, a j = 3 i traži se vjerojatnost P(2,3). Očigledno je da A
ima veće šanse za pobjedu. Tražimo algoritam koji za zadane i, j računa P(i, j).
Vrijedi relacija:
P(i, j) =
1
za i = 0, j > 0
0
za i > 0, j = 0
1
1
P(i 1, j )
P(i, j 1)
2
2
za i > 0, j > 0
Prva dva reda odgovrajau situaciji kada je jedan od igrača pokupio sve bodove, treći
red opisuje situaciju kada se igra bar još jedan dio igre u kojem A ima 50% šanse da dobije
bod. Ako dobije vjerojatnost konačne pobjede mu je P(i-1, j), a ako izgubi vjerojatnost je
P(i, j-1).
Gore navedena relacija može se iskoristiti za rekurzivno računanje P(i, j) na koje vodi
strategija podijeli pa vladaj no tako dobiveni algoritam je neefikasan jer se iste vrijednosti
računaju mnogo puta.
24
Algoritmi i logička struktura programa
P(2,3)
P(1,3)
P(0,3)
P(1,2)
P(2,2)
P(1,2)
P(2,1)
P(0,2) P(1,1) P(0,2) P(1,1)
P(0,1) P(1,0)
P(1,1) P(2,0)
P(0,1) P(1,0) P(0,1) P(1,0)
Ukupno se računa: P(0,1)-3 puta; P(1,0)-3 puta; P(0,2)-2 puta; P(1,1)-3 puta; P(2,0)-1 put;
P(1,2)-2 puta; P(0,3)-1 put; P(1,3)-1 put; P(2,2)-1 put; P(2,1)-1 put; P(2,3)-1 put. Ukupno:
19 računanja.
Složenost ovog algoritma je O(2n), dakle vrlo velika. Strategija dinamičkog
programiranja vodi na ispunjavanje tablice pri računanju P(i, j) u kojoj i odgovara stupcima a
j retcima.
1
2
21
32
13
16
15
16
1
4
11
32
1
2
11
16
7
8
1
3
3
16
5
16
1
2
3
4
1
2
1
16
1
8
1
4
1
2
1
1
0
0
0
0
4
3
2
1
0
0
Bilo koji unutarnji element može se dobiti kao aritmetička sredina elementa ispod i
desno od njega. Tablica se popunjava od doljnjeg desnog kuta.
Složenost ovog algoritma je kvadratna, dakle puno bolja od eksponencijalne
složenosti algoritma dobivenog „podijeli pa vladaj“ metodom.
25
Algoritmi i logička struktura programa
Računanje n povrh m
Probajmo slijedeći problem riješiti rekurzivno. Znamo sljedeće:
n
1;
0
n
n
1;
n
n 1
n 1
m
m 1
m
Dakle, možemo napisati funkciju:
T
n
0
1; T
n
n
1; T
n
m
T
n 1
m 1
T
n 1
m
Provodeći ovaj algoritam zaključujemo da je on vrlo spor. Npr. za računanje 33 povrh
16 treba mu preko 30 sekundi na Core2Duo 1.93 GHz procesoru.
Iako rješenje na prvi pogled izgleda jednostavno, ovakva složenost se javlja upravo
zbog toga što se mnogo puta poziva rekurzija sa istim parametrima.
Slično kao i kod prijašnjeg problema, algoritam možemo poboljšati dinamičkim
programiranjem. Ideja je slijedeća:
Sve n povrh m koje izračunamo pamtimo u tablicu, a rekurziju koristimo samo ukoliko
neki par još nismo izračunali.
Ovakav pristup problemu naziva se „Top down“ pristup, jer krećemo od konačnog
problema. Postoji i drugi način da dinamičkim programiranjem riješimo problem, a naziva se
„Bottom up“ pristup. Drguim riječima, krećemo od početka i redak po redak ispunjavamo
tablicu. Taj algoritam je obična simulacija paskalovog trokuta.
1
1
1
1
1
1
2
1
3
4
3
6
1
4
.
.
26
1
Algoritmi i logička struktura programa
Problem 0/1 ranca (Knapsack problem)
Tijekom pljačke, lopov pronaĎe neke stvari koje ne može ponijeti jer ima premalu
torbu. Njegova torba može nositi teret od maksimalno W kilograma. Pronašao je n stvari
težine w1, w2, w3,...,wn i vrijednostima v1, v2, v3,..., vn. Problem je odrediti maksimalnu
vrijednost koju može ponijeti u torbi.
Recimo da torba može ponijeti 10 kg.
Stvar
Težina
Vrijednost
1
6 kg
30 kn
2
3 kg
14 kn
3
4 kg
16 kn
4
2 kg
9 kn
Dvije su varijacije ovog problema. Ako postoji neograničena količina stvari, optimalan
izbor bi bio pokupiti stvar broj 1 i dvije stvari broj 4, dakle vrijednost bi bila 48 kn. S drgue
strane, ako postoji samo jedan uzorak svake stvari, onda je optimalan izbro stvar 1 i stvar 4,
ukupne vrijednosti od 46 kn.
Problem bi se mogao riješti algritmom tipa podijeli pa vladaj koji bi generirao sve
moguće podskupove skupa predmeta {O1, O2, ..., On} i izabrati onaj s najvećom vrijednošću
uz dopuštenu težinu. Inače, takav se algoritam naziva algoritam grube sile, „brute force“).
Složenost algoritma je eksponencijalna, O(2n), jer je potrebno pronaći i provjeriti sve
moguće podskupove.
Broj kombinacija k-tog razreda od n elemenata bez ponavljanja – binomni koeficijenti
– je:
n!
k !( n k )!
n
k
.
Služeći se dinamičkim programiranjem problem možemo riješiti složenošću O(Wn).
27
Algoritmi i logička struktura programa
Ranac sa ponavljanjem
Počnimo s algoritmom kada je dozvoljeno ponavljanje. Kao i uvijek da bi dinamički
riještli problem moramo si postaviti pitanje „Koji su potproblemi?“
Označimo sa K(w) najveću moguću vrijednost koju može ponijeti ruksak kapaciteta W.
Probajmo to izraziti kao potproblem.
Dakle, ako je K(w) optimalna solucija za težinu w, te sadrži stvar i, onda izbacivanje
i-te stvari iz torbe dobivamo optimalnu soluciju za težinu w - wi. Drugim riječima,
K ( w)
K ( w wi ) vi ,
za neki i . Pošto ne znamo točno koji je element najbolje dodati, isprobajmo sve kombinacije:
K (w) max K (w wi ) vi ,
i:wi w
gdje je uvjet da je maksimalna vrijednost prazne torbe jenaka 0.
Ranac bez ponavljanja
Druga varijanta je kad ponavljanja nisu dozvoljena, odnosno kad ima samo jedan
uzorak svake stvari. Sada funkciju K(w) moramo malo izmjeniti jer u prvom slučaju ne znamo
koje smo stvari stavili u torbu a koje nismo. Stoga, dodajemo novi parametar, 0
j
n.
K(w, j) sada predstavalja najveću moguću vrijednost torbe kapaciteta w i stvari od 1 do
j.
Kako sada možemo problem K(w, j) izraziti pomoću potproblema? Jednostavno, samo
gledamo je li je j-ti element potreban da bi smo dosegli maksimalnu vrijednost pri kapacitetu
w.
K (w, j ) max K (w wj , j 1) v j , K (w, j 1) .
Ovaj algoritam, baš kao i prošli, složenosti je O(nW).
28
Algoritmi i logička struktura programa
Najkraći put među čvorovima u grafu
Zadan je graf sa N čvorova. IzmeĎu odreĎenih čvorova postoji odreĎena udaljenost.
Traži se najkraći put izmeĎu svih čvorova zadanog grafa.
Dan je slijedeći graf:
Moramo pronaći najmanju udaljenost čvora A od ostalih čvorova, čvora B od ostalih
čvorova, itd. sve dok ne pronaĎemo sve najkraće udaljenosti. Da bi riješili ovaj problem
moramo ga svesti na manje potprobleme.
Što je ovdje potproblem?
Pošto tražimo najmanju udaljenost čvora u od čvora v, a da kao meĎučvorove možemo
koristit sve čvorove u grafu, potproblemom možemo smatrati, pronaći najkraći put od u do v
koristeći samo k čvorova.
Kada je k jednak 1 potproblem je jednostavan. Porastom broja k raste i težina
problema. Rješenje polaznog problema dobivamo za k = N – 1.
Označimo sa dist(u, v, k) najmanju udaljenost od čvora u do v, a da pritom kao
meĎučvorove koristimo samo čvorove od {1,...,k}. Pri čemu je dist(u, v, 0) direktna veza
izmeĎu čvorova u i v, ako ona postoji.
Sada možemo reći da koristeći čvor k dobivamo manju udaljenost ako i samo ako je
udaljenost od čvora u do čvora k zbrojena sa udaljenošću od čvora k do čvora v manja od
udaljenosti čvora u do čvora v koristeći čvorove od {1, ... , k – 1}.
Odnosno,
dist (u , k , k 1) dist (k , v, k 1)
29
dist (u , v, k 1) .
Algoritmi i logička struktura programa
POHELPNI PRISTUP
U mnogim algoritmima opitmizacije potrebno je napraviti niz izbora. Strategiju
dinamičkog programiranja često koristimo pri rješavanju takvih problema, gdje se optimalno
rješenje traži primjenom rekurzije računajći od najmanjih problema prema složenijim
(„bottom up“). Nažalost, strategija dinamičkog programiranja nekad dovodi do neefikasnih
algoritama, najčešće zbog predugih vremenskih izvršavanja. Stoga, u takvim slučajevima
alternativnu tehniku koju koristimo je strategija pohlepnog algoritma.
Ova strategija najčešće dovodi do jednostavnih i veoma brzih algoritama, ali nažalost
nije toliko moćna kao dinamičko programiranje. Tehnika pohelpnog pristupa ne daje uvijek
optimalno rješenje, no iako neda optimalno rješenje, često vodi na novu strategiju razvoja
algoritma koji je efikasniji od prijašnjeg.
Tehnikom pohelpnog pristupa, rješenje zadanog algoritma se konstruira u nizu koraka.
U svakom se koraku bira mogućnost koja je lokalno optimalna u nekom smislu. Zamisao je da
će nas takvi optimalni koraci devesti do globalnog optimalnog rješenja.
Kako bismo ilustrirali što je to pohlepni pristup razradit ćemo nekoliko primjera:
Trgovac vraća mušteriji iznos od 62 kn, na raspolaganju su mu novčanice od 50, 20,
10, 5 i 1 kn. Večina će ljudi instiktivno vratiti jednu novčanicu od 50 kn, jednu od 10 kn i
dvije od 1 kn. Takav algoritma vraća odreĎen iznos uz najkraću moguću listu novčanica.
Znači, izabere se najveća novčanica koja ne prelazi ukupnu sumu, stavlja se na listu za
vraćanje, oduzme se od ukupnog iznosa, te se postupak ponavlja sve dok se ne vrati odreĎen
iznos. Ovakva strategija nas je dovela do najefikasnijeg rješenja, ali samo zahvaljujući
specijalnim svojstvima odreĎenih novčanica.
Primjer kad pohelpni pristup ne funkcionira je slijedeći. Što ako je potrebno vratiti 15
kn pomoću novčanica od 11, 5 i 1 kn. Pohlepni algoritam prvo vraća 11 kn i tada mu preostaje
samo da vrati četiri novčanice od 1 kn. Znači ukupno 5 novčanica, dok bi optimalno rješenje
bilo vratiti 3 puta po 5 kn.
Na sličan način pohelpni pristup možemo primijeniti i na problem 0/1 ranca.
Generalizirajmo prijašnji problem.
Dano je n novčanica kojima možemo isplaćivati iznos: {A[0], A[1],...,A[N-1]}. I dan
nam je iznos koji trebamo vratiti. Već smo uočili da pohlepni pristup ne daje uvijek optimalno
rješenje. Stoga je bolje koristiti dinamičko programiranje.
30
Algoritmi i logička struktura programa
Označimo sa P(n, k) minimalan br. novčanica da se isplati iznos od k kuna koristeći
novčanice od A[0] do A[n]. Možemo zaključiti da ako moramo isplatiti 14 kn novčanicama
od 8, 5 i 2 kn, da nam je optimalno rješenje: ili ako isplaćujemo 14 kn bez zadnje novčanice
ili ako dodajemo i zadnju novčanicu i gledamo minimalno rješenje za k – A[n]. Zato pišemo:
P(n, k ) min P(n 1, k ),1 P(n, k A n ) .
Problem trgovačkog putnika (TSP)
Trgovački putnik želi posjetiti niz gradova i vratiti se u početni. Ako znamo vrijeme
putovanja izmeĎu svaka dva grada, kako napraviti plan putovanja da svaki grad osim
polaznog posjeti jednom a da ukupno vrijeme putovanja bude najmanje moguće?
Gradove predočavamo čvorovima, a put bridovima grafa. Udaljenost računamo kao
euklidsku udaljenost dviju točaka u ravnini.
Ovaj problem je NP težak, što znači da ne postoji polinomijalni algoritma koji ga
egzaktno rješava.
Evo približnog pohlepnog algoritma:
Označimo sa Eg skup svih bridova u polaznom grafu. Cilj nam je u svakom trenutku
odrediti što bi nam bilo najbolje. U skup E stavljamo najkraći brid iz skupa Eg \ E sa
svojstvom da;
1) Brid b ne prouzroči da neki vrh T bude trećeg stupnja (odnosno, da iz tog grada ima 3
različita puta – prema 3 različita grada)
2) Brid b neće zatvoriti krug, osim ako to nije zadnji grad (odnosno u skupu E se nelazi N
– 1 bridova)
31
Algoritmi i logička struktura programa
Rješenje spremamo u graf T(V, E) koji je na početku prazan. Gledajući gornji graf,
dodajemo najkraći brid. To je (d, e) = 3. Sada u skupu E imamo {(d,e)}. Dalje dodajemo
najkraći brid koji zadovoljva oba uvjeta. To su: (b, c), (a, b), (e, f). Svi su oni duljine 5.
Vidimo da nije važan redoslijed kojim dodajemo u graf. Sada je E = {(d, e), (b, c), (a, b), (e,
f)}. Naš graf T igleda:
Idući najkraći brid u grafu je (a, c) ali on bi zatvorio krug pa ga ne dodajemo, slično
postupamo i sa bridom (f, d).
Idući najkraći je (c, d) duljine 14. On zadovoljava oba uvjeta te ga dodajemo. Od svih
ostalih bridova jedino brid (a, f) zadovoljava uvjete. Dodajemo ga. Dobili smo konačno
rješenje duljine 50.
32
Algoritmi i logička struktura programa
Opet možemo uočiti da pohlepni pristup ne daje optimalno rješenje jer je najkraći
put jednak 48.39, graf izgleda ovako:
Primjer 1)
Mirko je na dar dobio čokoladu sa m × n kockica. On je jako praznovjeran i moram ju
prvo razlomiti na djelove koji su kvadrati (veličine k × k kockica). Mirko želi što prije
moguće početi jesti čokoladu pa ga zanima koliko je najmanje lomljena potrebno.
Vidimo da smo ovu čokoladu sa 5 × 3 kockica lomili 3 puta.
Pogledajmo najprije pohelpni pristup:
Ako je m > n, odlomimo kvadrat dimenzija n × n i komad čokolade dimenzija (m – n)
× n, a ako je n > m, odlomimo kvadrat dimenzija m × m i ostane nam komad čokolade
dimenzija m × (n – m).
Dakle, u ovom algoritmu prvo odlomimo najveći mogući kvadrat, pa najveći mogući
kvadrat od ostatka itd. Ali se takoĎer lako uočava da to nije optimalno rješenje (čokolada 5 ×
6).
Kao i problem sa novčanicama, tako i ovaj možemo riješiti dinamičkim
programiranjem. Označimo sa P(m, n) minimalan broj lomova čokolade sa m × n kockica.
Čokoladu možemo prelomiti nakon 1, 2, 3,..., (m-1) retka ili nakon 1, 2, 3,..., (n-1)
stupca. Ako prelomimo nakon i-tog retka onda je broj lomova jednak:
P(i, n) + P(m-i, n) +1
33
Algoritmi i logička struktura programa
Stoga tražimo optimalno mjesto za lom.
P(m, n) = 0 ako je m = n.
P(m, n) min mini P(m i, n) P(i, n) 1 , min j P(m, n
j) P(m, j) 1
Koristeći gornju formulu možemo jednostavno „top down“ pristupom izračunati broj
lomova.
BACKTRACKING
Strategija odustajanja ili backtracking jedna je od vrlo općenitih tehnika koje se
primjenjuje za teške kombinatorne probleme. Rješenje nekog problema traži se
sistematskim ispitivanjem svih mogućih kombinacija. Prostor rješenja prikazujemo ureĎenim
stablom gdje korijen predstavlja sve moguće n-torke, a dijete korijena predstavlja sve n-torke
gdje prva komponenta (x1) ima odreĎenu vrijednost. Rješenje problema odgovara jednom listu
stabla problema. Kako bi lakše dočarali ureĎeno stablo, prikazat ćemo primjer:
Ako se rješenje problema može prikazati kao ureĎena trojka (n=3) gdje je x1 iz skupa
S1 = {1, 2, 3, 4}, x2 iz skupa S2 = {1, 2} i x3 iz skupa S3 = {1, 2, 3}, prostor rješenja se
prikazuje gornjim grafom.
Pri rješavanju problema koristimo osnovni rekurzivni algoritam koji simultano
generira i ispituje čvorove u stablu rješenja. Ako čvor predstavlja rješenje poduzima se neka
odgovarajuća akcija, a ako čvor nije rješenje generiraju se njegova djeca. Na početku imamo
samo korijen stabla. Završetak je kada se pronaĎe rješenje. Pošto veličina prostora rješenja
raste eksponencijalno dobar algoritam strategije povlačenja nikad ne genrira cijelo stablo,
34
Algoritmi i logička struktura programa
nego odustaje od grana za koje uspije utvrditi da ne vode do rješenja. U postupku generiranja
čvorova provjeravaju se ograničenja koja n-torka mora zadovoljiti da bi zaista bila rješenje.
Strategija povlačenja često se rabi u problemima optimizacije gdje se od svih mogućih
rješenja traži ono koje je najoptimalnije. Optimalnost se mjeri funkcjom koju je potrebno
minimalizirati ili maksimalizirati. Ovisno o problemu funkciju interpretiramo kao cijenu,
zaradu, trošak ili slično. Osim što odustajemo od grana koje ne vode do rješenja odustajemo i
od onih grana koje ne vode do boljeg rješenja. Takva varijanta algoritma, naziva se algoritam
grananja i preskakanja (branch and bound).
Problem n kraljica
Na šahovskoj ploči veličine n × n polja treba postaviti n kraljica tako da se one
meĎusobno ne napadaju.
Rješenje:
Očito je da svaka kraljica mora biti u posebnom retku ploče, pa onda možemo uzeti da
je i-ta kraljica u i-tom rektu, stoga se rješenje problem može prikazati kao n-torka (x1, x2, x3,
..., xn), gdje je xi indeks stupca u kojem se nalazi i-ta kraljica. Organičenja koje se moraju
zadovoljiti izvode se iz zahtjeva da se niti jedan par kraljica ne smije nalaziti u istom stupcu i
istoj dijagonali. Kao primjer razmotrimo situaciju kada je n = 4. Strategija povlačenja generira
stablo rješenja:
35
Algoritmi i logička struktura programa
Crtkano su označeni oni čvorovi koje je algoritam odbacio odmah u postupku
generiranja jer krše ograničenja. Rad algoritma prekinut je čim je naĎeno prvo rješenje.
Rješenje je: {2, 4, 1, 3}.
Slično ovom primjeru možemo napraviti algoritam za odreĎivanje optimalnog poteza
u igri križić kružić.
Križić – kružić
Zadana je tablica za igru križić kružić na kojoj su već odigrani neki pozeti. Treba
utvrditi koji igrač ima strategiju koja vodi do pobjede, te koji je potez optimalan.
Pretopostavimo da je na potezu igrač „x“. Ako postoji način da on pobijedi, toj se
situaciji dodijeli oznaka 1. Ako ne može pobijediti ali može igrati neriješeno, situacija se
označava sa 0, a ako gubi kako god igrao situacija se označava s -1. Slično tome ako je „o“ na
potezu, situaciju u kojoj on može pobijediti označimo sa -1, kada može igrati najviše
neriješeno označimo sa 0 i kada gubi sa 1.
Zadana je slijedeća situacija:
36
Algoritmi i logička struktura programa
Na potezu je križić i ima 3 slobodna polja na koja može odigrati.
Ovdje ide stablo rješenja.. al mi se nije dalo crtat!
Strategijom odustajanja dobijemo stablo situacija. Lijevo dijete dobiva oznaku 1 jer je
pobjeda za „x“. Desno dijete je dobilo oznako 0 jer je na pozetu „o“, a ako on odigra prvi
potez rezultat je neriješen, a ako odigra drugi potez, pobejĎuje „x“. Srednje djete dobiva
oznaku -1 jer je ovisno o tome što igra „o“, „x“ gubi ili igra neriješeno.
Iz ovog je jasno da je oznaka svakog čvora u kojemu je na potezu „o“ jednaka
minimumu svih oznaka djece i analogno ako je na potezu „x“ oznaka čvora je maksimum svih
oznaka djece.
Dakle algoritam rješavanja je slijedeći:
Pobjednika odreĎujemo konstruirajući stablo svih situacija dostižljivih iz zadane
situacije; korijen stabla je zadana situacija ,a djeca nekog čvora su situacije do kojih se može
doći jednim potezom iz tog čvora.
Listovi stabla predstavljaju kraj igre.
37
Algoritmi i logička struktura programa
ALGORITMI SORTIRANJA
Kao uvod u algoritme sortiranja proučit ćemo nekoliko osnovnih metoda koje su
prikladne za sortiranje manjih datoteka ili datoteka sa specijalnom strukturom. Postoji
nekoliko razloga zbog kojih je dobro analizirati ove jednostavnije metode; npr., predstavljaju
nam relativno jednostavan način da naučimo terminologiju i jednostavnije mehanizme
sortiranja. Na taj način dobivamo dobru pozadinu za daljnje proučavanje složenijih
algoritama. Nadalje, nekada je bolje koristiti jednostavnije metode nego one složenije.
Algoritam sortiranja se u programu najčešće koriste samo jedanput, ili samo nekoliko puta;
ako je broj elemenata koje treba sortirati relativno mali (< 500), efikasnije je iskoristiti
jednostavniju metodu sortiranja. Osim datoteka sa malim brojem elemenata, relativno lako se
sortiraju i datoteke koje su skoro sortirane. U takvim situacijama takoĎer je bolje koristiti
jednostavnije metode.
Kao i obično, najvažnija stvar, koja nas zanima, je brzina sortiranja, odnostno
vremenska složenost. Vidjet ćemo da elementarne tehnike sortiranja su kvadratne složenosti
(O(n2)), dok oni najbriži algoritmi sortiranja sortiraju brzinom N log N, O(N log N).
Slijedeća stvar koju moramo uzeti u obzir je prostorna složenost. Teoretski se
algoritmi sortiranja dijele u tri skupine: algoritmi koji sortiraju na mjestu i ne zahtijevaju
dodatnu memoriju, algoritmi koji koriste vezane liste („linked list“) i zahtijevaju N dodatnih
mjesta u memoriji za pokazivače i algoritmi kojima je potrebna dodatna memorija da čuvaju
još jedan niz.
38
Algoritmi i logička struktura programa
SELECTION SORT
Jedan od najjednostavnijih algoritama sortiranja je selection sort, a radi na slijedeći
način:
Prvo pronaĎe najmanji element u nizu i zamijeni ga sa elementom na prvom mjestu,
zatim pronaĎe drugi najmanji element i zamjeni ga sa elementom na drugom mjestu i tako
dalje dok ne sortiramo cijeli niz. Metoda se naziva selection sort zbog toga što neprestano
odabire najamanji preostali element u nizu.
U prvom koraku pretražujemo sve elemente u nizu (N), u drugom koraku pretražujemo
N-1 elemente itd do N-tog koraka gdje pretražujemo samo jedan element. Stoga je složenost
algoritma kvadratna, O(N2).
INESERTION SORT
Baš kao što i samo ime govori algoritam ubacuje svaki član na njegovo mjesto u
završnoj listi. Najednostavnija implementacija ovog algoritma zahtijeva dvije liste – početnu
listu i listu u koju ubacujemo sortirane elemente. Da bi uštedjeli memoriju možemo koristit i
jednu listu tako što ćemo trenutni element zamjeniti s prethodnikom ukoliko je prethodnik
veći te postupak i taj postupak ćemo ponavljati dok element ne doĎe nas svoje mjesto.
Sličan algoritam čovjek nesvjesno koristi pri slaganju karata u nekoj kartaškoj igri.
Kao i prethodni, ovaj algoritam je kvadratne složenosti.
Iako su svi jednostavni algoritmi sortiranja kvadratne složenosti, ovaj algoritam je
najefikasniji. Čak duplo efikasniji od „bubble sorta“ i 40% efikasniji od „selection sorta“.
39
Algoritmi i logička struktura programa
BUBBLE SORT
Bubble sort je najstariji i najjednostavniji algoritam sortiranja koji se koristi, ali
nažalost i najsporiji je.
Bubble sort radi tako što svaki element usporeĎuje sa susjednim elementom i
zamijenjuje ukoliko je to potrebno. Algoritam ponavlja proces sve dok ne proĎe kroz sve
elemente a da nije napravio ni jednu zamjenu.
Ovaj algoritam je najsporiji u praktičnoj primjeni, no ako je lista kojim slučajem već
sortirana on će ju proći u linearnom vremenu, za razliku od „insertion sorta“ i „selection
sorta“.
QUICK SORT
Definitivno, quick sort, je jedan od najkorištenijih algoritama za sortiranje.
Algoritam je izmišljen 1960. godine, a izmislio ga je C.A.R. Hoare i od tad ga mnogi ljudi
proučavaju u nadi da ga poboljšaju. Vrlo je popularan upravo zbog toga što ga nije teško
implementirati, a i funkcionira sa različitim tipovima podataka i najvažnije od svega, najbrži
je danas poznati algoritam za sortiranje. Vremanska složenost mu je N log N, a u najgorem
slučaju kvadratna.
Algoritam je zasnovan na strategiji podijeli pa vladaj i svodi se na slijdeće:
1) Odabriemo jednog člana niza, tzv. pivota
2) Raspodijelimo niz tako da sve članove manje od pivota stavimo lijevo od njega, a
sve članove veće od pivota stavimo na njegovu desnu stranu. Očito je da je pivot
na svom mjestu (na tom će mjestu bit i u sortiranoj listi).
3) Rekurzivno sortiramo svaki podniz na isti način (imamo 2 podniza, prvi je s lijeve
strane pivota, a drugi s desne strane, pivot nam je slučajno odabrani element u
nizu, stoga slučajno odabrani element može biti i najmanji i najveći član pa imamo
samo jedan podniz).
40
Algoritmi i logička struktura programa
Ovdje ide još jedna slika!!
Rekurzija se prekida na nizovima od jednog ili niti jednog elementa, koji su sami po
sebi sortirani. Quick sort, u svojoj iteraciji stavlja barem jedan element niza na svoju konačnu
poziciju.
Možemo primijetiti da ako u nizu od N članova uzememo da je pivot maksimalan
element onda ćemo ga staviti na kraj, u koliko u slijdećiem podnizu opet odaberemo
maksimalan element opet ćemo ga staviti na kraj i dobiti samo jedan podniz, stoga ako stalno
uzimamo najveći element u nekom nizu složenost će biti kvadratna.
U ovom algoritmu ključno je kako ćemo dovesti pivota na pravo mjesto. Odnosno,
efikasno moramo izvesti podjelu na potprobleme.
Dovođenje pivotnog elementa na pavo mjesto
Primjer) Imamo listu L = (26, 5, 27, 1, 61, 11, 59, 15, 48, 19)
Uzmimo da je pivotni element a1 – 26.
Postavimo dva kursora (l i r):
Kursor l kreće od drugog elementa dok kursor r kreće od zadnjeg elementa. Kursor l
ide udesno dok ne naiĎe na element koji je veći od pivota dok kursor r ide nalijevo dok ne
naiĎe na element koji je manji od pivota.
Dakle, kursor l se pomiće do prvog većeg broja od 26.
Kursor r se pomiće do prvog broja manjeg od 26, dakle ostaje na mjestu. Elementi na
kojima su kursori stali se zamijene.
41
Algoritmi i logička struktura programa
Kursori se nastavljaju pomicat po istoj logici sve dok se ne prekriže. Kada se prekriže
pivotni element zamijenjujemo sa onim elementom na koji pokazuje kursor r. Sada niz
izgleda:
Primjećujemo da je pivotni element na pravome mjestu. Isti postupak primijenjujemo i
na podliste.
42
Algoritmi i logička struktura programa
ZAKLJUČAK
Svakim danom sve više i više primjećujemo kako nas ogromni val nove tehnologije
preplavljuje. Iako su nam sada samo stopala u vodi, ubrzo ćemo svi primijetiti da je
tehnologija ta koja će nas u budućnosti kontrolirati, na taj način, što ćemo ovisiti o njoj kao
što ovisimo o hrani i piću. Govorim ovo jer znam da se iza svake sprave, iza svakog računala i
iza svakog stroja koji ima neku namjenu krije neki algoritam koji ga upravlja, koji mu govori
što da radi. Razumijevanje načina na koji radi stroj može nas dovesti do znatne uštede novaca
i vremena, jer je već i danas većina stvari kompjutorizirana, a razumijevanje algoritma kojim
radi odreĎen stroj nam može znatno pomoći pri korištenju istoga.
TakoĎer, algoritmi nemaju samo primjenu u računalsvu, jer informatika nije sama sebi
svrha, odnosno samo s informatikom ne možemo skoro ništa. Kao što sam već rekao u uvodu,
algoritmi su svuda oko nas, a sposobnost raščlanjivanja problema na manje probleme koje je
relativno lako riješiti nam svakako mogu pomoći u svakidašnjem životu.
Ukoliko pogledamo oko sebe, shvatit ćemo da je svaka stvar sačinjena od manjih
stvari, a te manje stvari zajedno čine neku cjelinu koja funkcionira. Ista stvar je i sa
odreĎenim problemom. Ukoliko shvatimo manji problem i uspijemo pronaći način na koji će
više takvim malih problema sačiniti veliki, ustvari smo riješili problem.
Najljepša stvar u cijeloj priči je ta što je odgovor na večinu pitanja već dan. Samo
treba pogledat oko sebe i proučiti malo prirodu, jer mravi kad prolaze kroz mravinjak, oni
prolaze najkraćim putem, baš isto što i trgovački putnik želi.
Osim što sam ovim radom htio,izmeĎuostalog, pomoći budućim učenicima, koji se
žele baviti informatikom, da lakše shvate odreĎene pristupe nekim problemima i da dobiju
neke osnove koje će im itekako dobro doći kao budućim informatičarima, želio sam i
razuvjeriti one ljude koji misle da su matematika i informatika nekreativne znanosti.
Nekad se rješenja kriju u tako jednostavnim stvarima, prejednostavnim da bi čovjek,
koji se na nekoj hijerahiji stavlja na vrh piramide, uspio shvatiti.
43
Algoritmi i logička struktura programa
LITERATURA
Bujanovid, Z., Jelaska, I., Puljid, K., Strukture podataka i algoritmi – skripta, PMF, Zagreb, 2008.
Dsagupta, S., Papadimitrion, C. H., Vazirani, U. V., Algorithms, Berkley, USA, 2006.
Drozdek, A., Data structures and Algorithms in C++, Brooks/Cole, USA, 2001.
Knuth, D., The art of computer programming, Addison-Wesley, Stanford University, 1997.
Manager, R., Marušid, M., Strukture podataka i algoritmi - skripta, PMF, Zagreb, 2003.
Sedgewich, R., Algortihms, Addison-Wesley, USA, 1983.
http://www.csc.liv.ac.uk/~ped/teachadmin/algor/intro.html
http://www.nist.gov/dads/
44