RAČUNALNIŠTVO IN INFORMACIJSKE TEHNOLOGIJE OSNOVE ALGORITMOV NIKOLA GUID Fakulteta za elektrotehniko, računalništvo in informatiko Maribor, 2011 Kazalo 5 Vračanje (sestopanje) 5.1 Splošna metoda . . . . . . . 5.2 N kraljic na šahovsko desko 5.3 Vsota podmnožic . . . . . . 5.4 Barvanje grafov . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-1 5-2 5-4 5-15 5-21 Poglavje 5 Vračanje (sestopanje) Obstajajo problemi, ki imajo eksponentno časovno zahtevnost. Takim problemom rečemo, da so težki (hard ). Če je eksponentni problem dokazano eksponentni, mu rečemo, da je NP-polni (NP-complete). Mnogi od teh problemov so za prakso pomembni, zato se ne moremo kar vdati in storiti ničesar. V tem poglavju spoznamo en način obravnave teh težkih problemov, tj. vračanje ali sestopanje (backtracking). Z vračanjem je mogoče rešiti kar velike primerke eksponentnih problemov. Vračanje je izboljšava grobega iskanja, ko nekatere naslednike, za katere vemo, da ne pripeljejo do rešitve, zavrnemo. Čeprav problem še zmeraj ostane eksponentni, lahko s to strategijo v splošnem rešimo največkrat dovolj velike primerke. Vračanje temelji na konstrukciji drevesa prostora stanj (state-space tree), katerih vozlišča pomenijo določene izbire. Dana morata biti začetno in končno (ciljno) stanje. V trenutnem stanju uporabimo eno od možnih pravil, ki nas pripelje v drugo stanje. Če naletimo na stanje, iz katerega ni več mogoče tvoriti novih stanj, se vrnemo na predhodno stanje, od koder poskušamo najti drugo novo stanje. Strategijo prav zaradi te lastnosti imenujemo vračanje. Vračanje deluje podobno kot iskanje z razvijanjem v globino, kot smo ga že obravnavali v poglavju Zmanjšaj in vladaj, samo da tu na tekočem koraku ne poiščemo vseh stanj, ki izhajajo iz danega stanja, temveč izberemo samo eno od izhajajočih stanj. V terminologiji teorije grafov ustreza izbiri enega novega stanja tvorba (generation) vozlišča. Prav zaradi takega napredovanja v globino drevesa Kozak [Kozak, 1997] in Vilfan [Vilfan, 1998] tej strategiji pravita sestopanje. 5-2 5.1 Splošna metoda 5.1 Splošna metoda V tem poglavju se bomo omejili na probleme, katerih rešitev je mogoče zapisati kot vektor x = [x[1] x[2] . . . x[n]]T , kjer izbiramo komponente x[i] (i = 1, 2, . . . , n) iz končnih množic S[i] (x[i] ∈ S[i]). Velikost množice S[i] je m[i], pri čemer je m[i] < ∞. Problemi, ki jih rešujemo z vračanjem, zahtevajo, da vse rešitve izpolnjujejo množico omejitev. Omejitve delimo v eksplicitne in implicitne. Eksplicitne omejitve se kažejo v omejevanju števila vrednosti komponente x[i] (i = 1, 2, . . . , n). Tako lahko x[i] zavzame le vrednosti iz dane množice S[i], torej x[i] ∈ S[i]. Primer eksplicitne omejitve je: x[i] = 0 ali 1, če ima množica S[i] samo dva elementa (S[i] = {0, 1}). Vektor x, čigar komponente izpolnjujejo eksplicitne omejitve, definira prostor rešitve (solution space). Velikost tega prostora določa naslednji zmnožek: p(n) = m[1]m[2] . . . m[n]. Zgled 5.1. Vzemimo, da ima rešitev obliko x = [x[1] x[2]]T , pri čemer so x[1] ∈ S[1], x[2] ∈ S[2], S[1] = {0, 1, 2} in S[2] = {1, 0}. Torej velja m[1] = 3, m[2] = 2 in n = 2. Vseh rešitev je p(2) = m[1]m[2] = 3 · 2 = 6. Prostor rešitev lahko prikažemo z drevesom z globino 2 (slika 5.1). Vsaki veji na globini i pripada ena vrednost i-te komponente vektorja x. Vseh možnih stanj vektorja x je p(n), kar je toliko, kot je listov drevesa. V našem primeru je p(2) = 6. Globina drevesa ustreza številu komponent vektorja x, v našem primeru je to 2. ♦ globina 0 x[1]=1 x[1]=2 x[1]=3 1 x[2]=1 x[2]=0 x[2]=1 x[2]=0 x[2]=1 x[2]=0 2 Slika 5.1: Drevo prostora stanj. Z implicitnimi omejitvami skušamo zmanjšati prostor rešitev. Pri tem si pomagamo s kriterijsko funkcijo f , ki nam že pri delnem vektorju [x[1] x[2] . . . x[i]]T , 5.1 Splošna metoda 5-3 ugotovi, ali ima smisel z določanjem naslednje komponente vektorja x[i + 1]. Torej vrednost f ([x[1] x[2] . . . x[i]]) nam pove ali z iskanjem rešitve nadaljevati ali nehati. Na ta način lahko pohitrimo reševanje. Čim ostrejše so implicitne omejitve, tem več poti bomo krajšali in s tem bo pregledovanje hitrejše in algoritem učinkovitejši. Algoritem vračanja najde rešitev pri manj poskusih kot p(n). Njegova osnovna ideja je v tem, da gradi vektor postopoma, komponento za komponento. Psevdokod strategije vračanja je: VRACANJE(n, S,resitev) 1 k←1 2 while k > 0 3 do if obstaja nepregledan x[k] ∈ S[k] and 4 LAHKO-VODI-K-CILJU(n, x, k) 5 then if k = n 6 then resitev ← resitev ∪ x 7 else k ← k + 1 % Stopi v globino (sestopi). % Od tod izvira ime sestopanje. 8 else k ← k − 1 % Vrni se. Od tod tudi ime vračanje. Komponente x[k] zadoščajo eksplicitnim omejitvam (x[k] ∈ S[i]) in implicitnim omejitvam (LAHKO-VODI-K-CILJU(n, x, k)). Vse rešitve vektorja x shranimo v množico rešitev, ki jo moramo pred klicem procedure izprazniti. Časovna zahtevnost Najslabša časovna zahtevnost je T (n) = O(p(n)) = O(Πni=1 m[i]). Implicitne omejitve v splošnem zmanjšajo časovno zahtevnost, za koliko pa je težko izračunati. Pomagali si bomo z merjenimi časi. 5-4 5.2 N kraljic na šahovsko desko 5.2 N kraljic na šahovsko desko Najznamenitejša uporaba strategije vračanja je postavitev osmih kraljic na šahovsko desko, tako da se med seboj ne napadajo. Procedura N-KRALJIC(n, rešitev) poišče vse postavitve n kraljic na šahovsko desko n × n, da se med seboj ne napadajo. Ko rešitev najde, jo shrani v množico rešitev. Množica rešitev mora biti pred klicem prazna. N-KRALJIC(n,resitev) 1 x[1] ← 0 2 k←1 % k je tekoča vrsta, x[k] je tekoči stolpec 3 while k > 0 4 do x[k] ← x[k] + 1 % premakni v naslednji stolpec 5 while x[k] ≤ n and NAPADENA(k, x) 6 do x[k] ← x[k] + 1 % kraljico moramo premakniti 7 if x[k] ≤ n % položaj smo našli 8 then if k = n % ali je rešitev kompletna? 9 then resitev←resitev ∪ x 10 else k ← k + 1 % pojdi v naslednjo vrsto % ali sestopi 11 x[k] ← 0 % pripravi novo kraljico 12 else k ← k−1 % položaj nismo našli, zato se vrni Preden se lotimo podrobne obravnave procedure N-KRALJIC(n,resitev) poskušajmo zgraditi Boolovo fukcijo NAPADENA(k, x). Vrstica i naj pripada i-ti kraljici (i = 1, 2, . . . , n). Z x[k] (x[k] = 1, 2, . . . , n) označimo stolpec, v katerem je i-ta kraljica (slika 5.2). i 3 2 1 1 2 3 4 x[i] Slika 5.2: Kraljice na šahovskem polju. Predpostavimo, da je i-ta kraljica na položaju (x[i], i) in k-ta kraljica na položaju (x[k], k) (slika 5.3). Kraljici se napadata, če ležita na premici z naslednjimi naklonskimi koeficienti: 5-5 5.2 N kraljic na šahovsko desko i i (x[i], i) (x[k], k) k x[i] x[k] x[i] Slika 5.3: i-ta in k-ta kraljica na šahovskem polju. ∞, 0, 1 in −1. Če je naklon i−k = ∞, x[i] − x[k] velja x[i] = x[k]. (5.1) Enačba 5.1 pove, da sta kraljici v istem stolpcu. Če je naklon i−k = 0, x[i] − x[k] velja i = k. (5.2) Enačba 5.2 trdi, da sta kraljici v isti vrstici. Če je naklon i−k = ±1, x[i] − x[k] velja |x[i] − x[k]| = |i − k|. (5.3) Enačba 5.3 pove, da sta kraljici na isti diagonali. Zgradimo Boolovo funkcijo NAPADENA(k, x), ki nam vrne vrednost FALSE, če k-to kraljico lahko postavimo na šahovsko desko, kar pomeni, da ni napadena od že postavljenih kraljic. Kraljice postavljamo tako, da damo v i-to vrstico samo i-to kraljico. Tako nam v funkcijo NAPADENA(k, x) ni treba neposredno vgraditi pogoja iz enačbe 5.2. NAPADENA(k, x) 1 i←1 2 while i < k 3 do if x[i] = x[k] or |x[i]-x[k]|=|i-k| 4 then NAPADENA←TRUE % k-ta kraljica je napadena % od i-te kraljice 5 exit(NAPADENA) 6 i ← i + 1 % k-ta kraljica ni napadena od i-te kraljice 7 NAPADENA←FALSE % k-ta kraljica ni napadena od nobene kraljice Funkcija NAPADENA pove, ali je k-ta kraljica, ki jo postavimo na šahovsko polje v k-to vrstico in x[k]-ti stolpec, napadena ali ne od kraljic na poljih v i-ti vrsti in 5-6 5.2 N kraljic na šahovsko desko x[i]-tem stolpcu (i = 1, 2, . . . , k − 1). Če je napadena, nam vrne vrednost TRUE, če ni napadena, pa vrednost FALSE. Zgled 5.2. Ponazorimo delovanje funkcije NAPADENA. Naj bo k = 2, x[1] = 1 in x[2] = 1. Položaj dveh kraljic kaže slika 5.4. Poženimo funkcijo: i 2 1 1 2 x[i] Slika 5.4: Postavitev prve in druge kraljice na šahovskem polju. 1. Vrstica 1: i = 1. 2. Vrstica 2: i = 1 < 2 = k. 3. Vrstici 3–4: Ker je x[1] = x[2], izstopimo z vrednostjo TRUE. To pomeni, da je druga kraljica napadena. ♦ Zgled 5.3. Ponazorimo še enkrat delovanje funkcije NAPADENA. Naj bo k = 2, x[1] = 1 in x[2] = 3. Položaj dveh kraljic kaže slika 5.5. Poženimo funkcijo: i 2 1 1 2 3 x[i] Slika 5.5: Postavitev prve in druge kraljice na šahovskem polju. 1. Vrstica 1: i = 1. 2. Vrstica 2: 1. iteracija zanke while: i = 1 < 2 = k. 3. Vrstica 3: Ker velja x[1] 6= x[2] (1 6= 3) in |x[1] − x[k]| 6= |i − k| (|1 − 3| 6= |1 − 2|), gremo na vrstico 6. 4. Vrstica 6: i = 1 + 1 = 2. 5. Vrstica 2: 2. iteracija zanke while: ker i = k (2 = 2), ne izvedemo zanke. 5-7 5.2 N kraljic na šahovsko desko 6. Vrstica 7: NAPADENA dobi vrednost FALSE. To pomeni, da druga kraljica ni napadena. ♦ Zgled 5.4. Zaradi preprostejše obravnave predpostavimo, da imamo šahovsko polje 4 × 4 s štirimi kraljicami (n = 4). Poženimo proceduro N-KRALJIC(4,rešitev): 1. Vrstica 1: x[1] = 0. 2. Vrstica 2: k = 1 3. Vrstice 3–12: 1. iteracija 1. zanke while, k = 1 > 0 (a) Vrstica 4: x[1] = 0 + 1 = 1 (b) Vrstica 5: 2. while se ne izvrši, ker ni izpolnjen drugi pogoj, tj. NAPADENA(1, x) = FALSE. (c) Vrstica 7: Ker je 1 ≤ 4 (1. if) in ker 1 6= 4 (2. if), gremo v vrstico 10. (d) Vrstici 10–11: k = 1 + 1 = 2 (sestopimo v globino) in x[2] = 0. Na koncu 1. iteracije 1. zanke while smo postavili 1. kraljico v polje (1, 1). 4. Vrstice 3–12: 2. iteracija 1. zanke while, k = 2 > 0 (a) Vrstica 4: x[2] = 0 + 1 = 1 (b) Vrstici 5–6: 2. while: ker velja x[2] = 1 ≤ 4 in NAPADENA(2, x)=TRUE, se 2. while izvrši: x[2] = 1 + 1 = 2. (c) Vrstici 5–6: 2. while: ker velja x[2] = 2 ≤ 4 in NAPADENA(2, x)=TRUE, se 2. while izvrši: x[2] = 2 + 1 = 3. (d) Vrstica 5: 2. while: ker velja x[2] = 3 ≤ 4 in NAPADENA(2, x)=FALSE, se 2. while ne izvrši. (e) Vrstica 7: Ker je 3 ≤ 4 (1. if) in ker 2 6= 4 (2. if), gremo v vrstico 10. (f) Vrstici 10–11: k = 2 + 1 = 3 (sestopimo v globino) in x[3] = 0. Na koncu 2. iteracije 1. zanke while smo postavili 2. kraljico v polje (3, 2) (slika 5.6). k 4 3 2 1 1 2 3 4 x[k] Slika 5.6: Postavitev prve in druge kraljice na šahovskem polju. 5-8 5.2 N kraljic na šahovsko desko 5. Vrstice 3–12: 3. iteracija 1. zanke while, k = 3 > 0 (a) Vrstica 4: x[3] = 0 + 1 = 1 (b) Vrstici 5–6: 2. while: ker velja x[3] = 1 ≤ 4 in NAPADENA(3, x)=TRUE, se 2. while izvrši: x[3] = 1 + 1 = 2. (c) Vrstici 5–6: 2. while: ker velja x[3] = 2 ≤ 4 in NAPADENA(3, x)=TRUE, se 2. while izvrši: x[3] = 2 + 1 = 3. (d) Vrstici 5–6: 2. while: ker velja x[3] = 3 ≤ 4 in NAPADENA(3, x)=TRUE, se 2. while izvrši: x[3] = 3 + 1 = 4. (e) Vrstici 5–6: 2. while: ker velja x[3] = 4 ≤ 4 in NAPADENA(3, x)=TRUE, se 2. while izvrši: x[3] = 4 + 1 = 5. (f) Vrstica 5: 2. while: ker ne velja x[3] = 5 ≤ 4, se 2. while ne izvrši. (g) Vrstica 7: Ker ne velja 5 ≤ 4 (1. if), gremo v vrstico 12. (h) Vrstica 12: k = 3 − 1 = 2. Vrnemo se na globino k = 2. Na koncu 3. iteracije 1. zanke while ugotovimo, da tretje kraljice ne moremo postaviti. 6. Vrstice 3–12: 4. iteracija 1. zanke while, k = 2 > 0 (a) Vrstica 4: x[2] = 3 + 1 = 4 (b) Vrstica 5: 2. while: ker velja x[2] = 4 ≤ 4 in NAPADENA(2, x)=FALSE, se 2. while ne izvrši. (c) Vrstica 7: Ker velja 4 ≤ 4 (1. if) in ker 2 6= 4 (2. if), gremo v vrstico 10. (d) Vrstici 10–11: k = 2 + 1 = 3 (sestopimo v globino) in x[3] = 0. Na koncu 4. iteracije 1. zanke while smo postavili 2. kraljico v polje (4, 2) (slika 5.7). k 4 3 2 1 1 2 3 4 x[k] Slika 5.7: Postavitev prve in druge kraljice na šahovskem polju. 5-9 5.2 N kraljic na šahovsko desko 7. Vrstice 3–12: 5. iteracija 1. zanke while, k = 3 > 0 (a) Vrstica 4: x[3] = 0 + 1 = 1 (b) Vrstici 5–6: 2. while: ker velja x[3] = 1 ≤ 4 in NAPADENA(3, x)=TRUE, se 2. while izvrši: x[3] = 1 + 1 = 2. (c) Vrstica 5: 2. while: ker velja x[3] = 2 ≤ 4 in NAPADENA(3, x)=FALSE, se 2. while ne izvrši. (d) Vrstica 7: Ker velja 2 ≤ 4 (1. if) in ker 3 6= 4 (2. if), gremo v vrstico 10. (e) Vrstici 10–11: k = 3 + 1 = 4 (sestopimo v globino) in x[4] = 0. Na koncu 5. iteracije 1. zanke while smo postavili 3. kraljico v polje (2, 3) (slika 5.8). k 4 3 2 1 1 2 3 4 x[k] Slika 5.8: Postavitev prvih treh kraljic na šahovskem polju. 8. Vrstice 3–12: 6. iteracija 1. zanke while, k = 4 > 0 (a) Vrstica 4: x[4] = 0 + 1 = 1 (b) Vrstici 5–6: 2. while: ker velja x[4] = 1 ≤ 4 in NAPADENA(4, x)=TRUE, se 2. while izvrši: x[4] = 1 + 1 = 2. (c) Vrstici 5–6: 2. while: ker velja x[4] = 2 ≤ 4 in NAPADENA(4, x)=TRUE, se 2. while izvrši: x[4] = 2 + 1 = 3. (d) Vrstici 5–6: 2. while: ker velja x[4] = 3 ≤ 4 in NAPADENA(4, x)=TRUE, se 2. while izvrši: x[4] = 3 + 1 = 4. (e) Vrstici 5–6: 2. while: ker velja x[4] = 4 ≤ 4 in NAPADENA(4, x)=TRUE, se 2. while izvrši: x[4] = 4 + 1 = 5. (f) Vrstica 5: 2. while: ker ne velja x[4] = 5 ≤ 4, se 2. while ne izvrši. (g) Vrstica 7: Ker ne velja 5 ≤ 4 (1. if), gremo v vrstico 12. (h) Vrstica 12: k = 4 − 1 = 3. Vrnemo se na k = 3. Na koncu 6. iteracije 1. zanke while smo ugotovili, da 4. kraljice ne moremo postaviti na desko. 5.2 N kraljic na šahovsko desko 5-10 9. Vrstice 3–12: 7. iteracija 1. zanke while, k = 3 > 0 (a) Vrstica 4: x[3] = 2 + 1 = 3 (b) Vrstici 5–6: 2. while: ker velja x[3] = 3 ≤ 4 in NAPADENA(3, x)=TRUE, se 2. while izvrši: x[3] = 3 + 1 = 4. (c) Vrstici 5–6: 2. while: ker velja x[3] = 4 ≤ 4 in NAPADENA(3, x)=TRUE, se 2. while izvrši: x[3] = 4 + 1 = 5. (d) Vrstica 5: 2. while: ker ne velja x[4] = 5 ≤ 4, se 2. while ne izvrši. (e) Vrstica 7: Ker ne velja 5 ≤ 4 (1. if), gremo v vrstico 12. (f) Vrstica 12: k = 3 − 1 = 2. Vrnemo se na k = 2. Na koncu 7. iteracije 1. zanke while smo ugotovili, da 3. kraljice ne moremo postaviti na desko. 10. Vrstice 3–12: 8. iteracija 1. zanke while, k = 2 > 0 (a) Vrstica 4: x[2] = 4 + 1 = 5 (b) Vrstica 5: 2. while se ne izvrši, ker ne velja x[2] = 5 ≤ 4. (c) Vrstica 7: Ker ne velja 5 ≤ 4 (1. if), gremo v vrstico 12. (d) Vrstica 12: k = 2 − 1 = 1. Vrnemo se na k = 1. Na koncu 8. iteracije 1. zanke while smo ugotovili, da 2. kraljice ne moremo postaviti na desko. 11. Vrstice 3–12: 9. iteracija 1. zanke while, k = 1 > 0 (a) Vrstica 4: x[1] = 1 + 1 = 2 (b) Vrstica 5: 2. while se ne izvrši, ker velja NAPADENA(4, x)=FALSE. (c) Vrstica 7: Ker velja 2 ≤ 4 (1. if) in ker 2 6= 4 (2. if), gremo v vrstico 10. (d) Vrstica 10–11: k = 1 + 1 = 2 (sestopimo v globino) in x[2] = 0. Na koncu 9. iteracije 1. zanke while smo postavili 1. kraljico v polje (2, 1). 5-11 5.2 N kraljic na šahovsko desko 12. Na ta način pridemo kmalu do 1. rešitve (slika 5.9): x[1] = 2, x[2] = 4, x[3] = 1, x[4] = 3. k 4 3 2 1 1 2 3 4 x[k] Slika 5.9: Prva postavitev vseh kraljic na šahovskem polju. 13. Kljub temu da smo našli rešitev, ponovno izvršimo 1. zanko while in premaknemo 4. kraljico v naslednji položaj: x[4] = 3 + 1 = 4. Ker je 4. kraljica nenapadena, jo moramo premakniti v naslednje polje (x[4] = 5), kar ima za posledico vračanje (k = 4 − 1 = 3). 14. V naslednji izvršitvi 1. zanke while dosežemo že x[3] = 5 in vračanje do k = 2. 15. Sledi ponovna izvršitev 1. zanke while, ko dobimo x[2] = 5 in vračanje do k = 1. 16. V novi izvršitvi 1. zanke while premaknemo 1. kraljico v tretji stolpec (x[1] = 2 + 1 = 3). Kmalu zatem najdemo še drugo rešitev: x[1] = 3, x[2] = 1, x[3] = 4, x[4] = 2. 17. Procedura se zaključi, ko k postane 0. Celoten postopek reševanja procedure N-KRALJIC podajamo v preglednici 5.1. Delovanje procedure N-KRALJIC lahko opišemo z drevesom stanj (slika 5.10). Vozlišča na sliki 5.10 predstavljajo tekočo podatkovno bazo, ki jo lahko vidimo na sliki 5.11. ♦ 5-12 5.2 N kraljic na šahovsko desko Preglednica 5.1: Rezultat delovanja procedure N-KRALJIC. k 0 1 2 3 2 3 4 3 2 1 2 3 4 4 3 2 1 2 3 4 4 3 2 1 2 3 4 3 2 3 2 1 0 x[1] 0 1 x[2] x[3] x[4] opomba začetni pogoji 3 >4 zmanjšamo k za 1 4 2 >4 zmanjšamo k za 1 zmanjšamo k za 1 zmanjšamo k za 1 3 >4 rešitev in vrnitev v 1. while zmanjšamo k za 1 zmanjšamo k za 1 zmanjšamo k za 1 2 >4 rešitev in vrnitev v 1. while zmanjšamo k za 1 zmanjšamo k za 1 zmanjšamo k za 1 >4 zmanjšamo k za 1 zmanjšamo k za 1 >4 >4 2 4 1 >4 >4 3 1 4 >4 >4 4 1 3 >4 2 >4 >4 >4 zmanjšamo k za 1 zmanjšamo k za 1 zmanjšamo k za 1 konec procedure 5-13 5.2 N kraljic na šahovsko desko nivo a 1 x[1] b x[2] x[3] 2 0 4 3 1 f 3 4 4 c d g 2 1 e h 3 x[4] 1 1 2 2 4 3 3 2 4 i rešitev rešitev Slika 5.10: Drevo stanj kot rezultat reševanja problema nenapadanja 4 kraljic. a b c d f g h i rešitev Slika 5.11: Stanja v vozliščih drevesa na sliki 5.10. e 5-14 5.2 N kraljic na šahovsko desko Rešitve so le listi z nivojem 4. Če ne bi upoštevali omejitev, bi zgradili drevo stanj s 44 = 256 listov (slika 5.12). x[1] 1 1 ... 4 x[2] x[3] x[4] 1 ... 4 1 ... 4 1 ... 4 1.. 1.. 1.. 1.. 1.. 1.. 1.. 1.. 1.. 1.. 1.. 1.. 1.. 1 ... 4 1 ... 4 4 3 2 .. 4 .. 4 ... 256 1 ... 4 Slika 5.12: Drevo stanj brez upoštevanja implicitnih omejitev. Časovna zahtevnost procedure N-KRALJIC Kozak je izmeril naslednjo časovno zahtevnost [Kozak, 1997]: T (n) = O(22,5n ). Ta vrednost je gotovo precej manjša od O(nn ), vendar je še vedno eksponentna. 5-15 5.3 Vsota podmnožic 5.3 Vsota podmnožic Pozitivno število M želimo razstaviti na pozitivne sumande, ki jih izbiramo iz množice znanih števil w[i], i = 1, 2, . . . , n. V literaturi je problem znan kot problem vsote množic (subset-sum problem). Iskano rešitev predstavimo z vektorjem x = [x[1] x[2] . . . x[n]], kjer komponento x[i] definiramo z: ½ 0, ˇce w[i] ni v vsoti x[i] = (5.4) 1, ˇce je w[i] v vsoti Vektor x je rešitev, če velja: n X x[i]w[i] = M. (5.5) i=1 Iz enačbe 5.5 lahko sklepamo, da lahko vsak sumand sodeluje v vsoti samo enkrat. Rešitev x gradimo postopoma in skušamo zavreči čimveč možnosti. Pri tem si pomagamo z omejitvenimi funkcijami. Denimo, da smo x zgradili do (k − 1)-te komponente, tj. x[k − 1]. Izbira naslednje komponente x[k] ne vodi k cilju, če M ne moremo doseči s preostalimi sumandi: k X x[i]w[i] + i=1 n X w[i] < M. (5.6) i=k+1 Cilja ne bomo dosegli tudi v primeru, če vsoto v naslednjem koraku presežemo: k X x[i]w[i] + i=1 min {w[i]} > M. k+1≤i≤n (5.7) Pogoj 5.7 pove, da je koristno, če sumande že na začetku uredimo v nepadajočem vrstnem redu. V tem primeru je: min {w[i]} = w[k + 1]. k+1≤i≤n (5.8) Pogoji, ki jih predstavljajo izrazi 5.5, 5.6 in 5.7, so tako imenovane implicitne omejitve. Preden zapišemo rekurzivni algoritem sestopanja za tvorbo vsote podmnožic števil, uvedimo nekaj spremenljivk. Spremenljivka dok naj predstavlja vsoto vključenih sumandov na tekočem koraku: dok = k−1 X i=1 x[i]w[i], (5.9) 5-16 5.3 Vsota podmnožic medtem ko odk pomeni največjo možno vsoto iz preostalih sumandov: odk = n X w[i]. (5.10) i=k Obe spremenljivki potrebujemo v tekočih omejitvenih pogojih. Elementi w[i] morajo biti razvrščeni v nepadajočem vrstnem redu. Da ima reševanje sploh smisel, mora veljati: w[1] ≤ M (5.11) in n X w[i] ≥ M. (5.12) i=1 Psevdokod algoritma za tvorbo vsote množic števil je: VSOTA-PODMNOZIC(n, w, M, k, dok, odk, resitev) 1 x[k] ← 1 % Predpostavimo, da je w[k] v rešitvi, tj. levi sin. 2 if dok + w[k] = M 3 then for i ← k + 1 to n 4 do x[i] ← 0 % Rešitev; preostale komponente so enake 0. 5 resitev ← [x[1] x[2] . . . x[n]] ∪ resitev 6 else if dok + w[k] + w[k + 1] ≤ M % S preostalim sumandom še lahko pridemo do rešitve. 7 then VSOTA-PODMNOZIC(n, w, M, k+1, dok+w[k], odk−w[k], resitev) % Sestopimo v levo, tj. generiramo levi sin. 8 if dok + odk − w[k] ≥ M and dok + w[k + 1] ≤ M % S preostalimi sumandi še lahko dosežemo rešitev. 9 then x[k] ← 0 % Sestopimo v desno, tj. generiramo desni sin. 10 VSOTA-PODMNOZIC(n, w, M, k + 1, dok, odk − w[k], resitev) Začetni klic danega algoritma mora imeti naslednje vrednosti parametrov: k = 1, dok = 0, odk = n X w[i], i=1 resitev = {}. Parameter k ustreza vrednosti globine, povečani za 1. 5-17 5.3 Vsota podmnožic Zgled 5.5. Število 10 razstavi s pomočjo štirih števil w = [4, 5, 5, 6]. 1. Proceduro pokličemo z naslednjimi vrednostmi: k = 1, dok = 0, odk = 4 X w[i] = 20, resitev = 0. i=1 Predpostavimo levi sin: x[1] = 1. Pogoj pri 1. if ni izpolnjen (0 + 4 6= 10). Pogoj pri 2. if je izpolnjen (0 + 4 + 5 ≤ 10), zato sestopimo v levo in generiramo levi sin x[1] = 1. 2. Proceduro pokličemo z naslednjimi vrednostmi: k = 2, dok = 4, odk = odk − w[1] = 16. Sedaj smo na globini 1. Predpostavimo levi sin: x[2] = 1. Pogoj pri 1. if ni izpolnjen (4 + 5 6= 10). Pogoj pri 2. if ni izpolnjen (4 + 5 + 5 ni manjše ali enako 10), zato pogledamo pogoja pri 3. if (4 + 16 − 5 ≥ 10 in 4 + 5 ≤ 10). Oba pogoja sta izpolnjena, zato generiramo x[2] = 0, tj. desni sin oziroma sestopimo v desno v globino 2. 3. Proceduro pokličemo z naslednjimi vrednostmi: k = 3, dok = 4, odk = odk − w[2] = 16 − 5 = 11. Predpostavimo levi sin: x[3] = 1. Pogoj pri 1. if ni izpolnjen (4 + 5 6= 10). Pogoj pri 2. if ni izpolnjen (4+5+6 ni manjše ali enako 10), zato pogledamo pogoja pri 3. if (4 + 11 − 5 ≥ 10 in 4 + 6 ≤ 10). Oba pogoja sta izpolnjena, zato generiramo x[3] = 0, tj. desni sin oziroma sestopimo v desno v globino 3. 4. Proceduro pokličemo z naslednjimi vrednostmi: k = 4, dok = 4, odk = odk − w[3] = 11 − 5 = 6. Sedaj smo na globini 3. Predpostavimo levi sin: x[4] = 1. Pogoj pri 1. if je izpolnjen (4 + 6 = 10), zato zapišemo rešitev. Ker preostalih komponent x[i] ni, se zanka for ne izvrši (i = 5 to 4). Rešitev je vektor x = [1 0 0 1]. Torej zadnji levi sin generiramo. Vstopimo v 3. if (4 + 6 − 6 ni večje ali enako 10). S tem so zaključili proceduro na globini 3. 5. Ker smo sestopali v globino po desni strani (razen na globini 0), se vrnemo na globino 0, ko smo poklicali VSOTA-PODMNOZIC v vrsti 7. Sledi izvršitev 3. if s starimi podatki: k = 1, dok = 0, odk = 20. Pogoja pri 3. if sta izpolnjena (0 + 20 − 4 ≥ 10) in (0 + 5 ≤ 10), zato generiramo x[1] = 0, tj. desni sin oziroma sestopimo v desno v globino 1. 5-18 5.3 Vsota podmnožic 6. Proceduro pokličemo z naslednjimi vrednostmi: k = 2, dok = 0, odk = odk − w[1] = 16. Predpostavimo levi sin: x[2] = 1. Pogoj pri 1. if ni izpolnjen (0 + 5 6= 10). Pogoj pri 2. if je izpolnjen (0 + 5 + 5 ≤ 10), zato sestopimo v levo, tj. generiramo levi sin x[2] = 1. Sestopimo v globino 2. 7. Proceduro pokličemo z naslednjimi vrednostmi: k = 3, dok = 5, odk = 11. Predpostavimo levi sin: x[3] = 1. Pogoj pri 1. if je izpolnjen (5 + 5 = 10), zato zapišemo rešitev. Preostale komponente x[i] dobijo vrednost 0. Zanka for se izvrši samo enkrat (i = 4 to 4) ali x[4] = 0. Torej zadnji levi sin generiramo (x[3] = 1). Rešitev je vektor x = [0 1 1 0]. Vstopimo v 3. if. Prvi pogoj je izpolnjen (5 + 11 − 5 ≥ 10), drugi pa ne (5 + 6 ni manjše ali enako 10), zato končamo s proceduro na globini 2. 8. Vrnemo se na globino 1, ko smo izvršili proceduro VSOTA-PODMNOZIC v vrsti 7. Sledi izvršitev 3. if s starimi podatki: k = 2, dok = 0, odk = 16. Pogoja pri 3. if sta izpolnjena (0 + 16 − 5 ≥ 10) in (0 + 5 ≤ 10), zato generiramo x[2] = 0, tj. desni sin oziroma sestopimo v desno v globino 2. 9. Proceduro pokličemo z naslednjimi vrednostmi: k = 3, dok = 0, odk = 11. Predpostavimo levi sin: x[3] = 1. Pogoj pri 1. if ni izpolnjen (0 + 5 6= 10). Pogoj pri 2. if ni izpolnjen (0+5+6 ni manjše ali enako 10), zato pogledamo prvi pogoj pri 3. if. Ta ni izpolnjen, saj (0 + 11 − 5 ni večje ali enako 10). Zaključimo proceduro na globini 2, ne da bi generirali levega sina x[3] = 1. Dani postopek reševanja lahko ponazorimo s preglednico 5.2. 5-19 5.3 Vsota podmnožic Preglednica 5.2: Rezultati delovanja procedure VSOTA-PODMNOZIC. k=1 dok 0 odk 20 k=2 dok odk 4 16 k=3 dok odk 4 11 k=4 dok x[1] 1 x[2] x[3] x[4] 0 0 4 0 odk 20 6 1! 0 0 16 1 5 0 11 16 1 0! 0 0 11 1? Opomba: Klicaj označuje konec zaporedja vrednosti x, ki predstavlja rešitev. Vprašaj pomeni, da končamo brez generacije levega sina x[3] = 1. Naš primer ima dve rešitvi: x = [1 0 0 1] in x = [0 1 1 0]. Slika 5.13 prikazuje drevo stanj, ki ga tvori procedura VSOTA-PODMNOZIC. Vozlišča so označena s trojico (k, dok, odk). Vrednost za k je enaka globini drevesa minus 1. V našem primeru smo poklicali proceduro VSOTA-PODMNOZIC sedemkrat. Drevo stanj brez implicitnih omejitev ima 2n − 1 = 24 − 1 = 15 vozlišč. ♦ 5.3 Vsota podmnožic 5-20 Slika 5.13: Drevo stanj procedure VSOTA-PODMNOZIC. Časovna zahtevnost procedure VSOTA-PODMNOZIC Iz meritev je Kozak [Kozak, 1997] določil, da je časovna zahtevnost algoritma približno 3 T (n) = O(2 4 n ), kar je nekaj bolje od direktnega pregledovanja, kjer bi bila zahtevnost O(2n ). 5-21 5.4 Barvanje grafov 5.4 Barvanje grafov Definicija 5.1. Graf G je m-barvljiv (m-colourable), če obstaja prireditev celih števil 1, 2, . . . , m, imenovanih barve, k vozliščem iz G, tako da nobeni sosedni vozlišči nimata enakih barv. Problem barvanja grafov imenujemo odločitveni problem m-barvljivosti (m-colourability decision problem). Zanimiv je optimizacijski problem m-barvljivosti, ki išče najmanjše celo število barv m, s katerim lahko še pobarvamo graf G. Definicija 5.2. Kromatično število ( chromatic number) v G je najmanjše celo število k, tako da se graf G da pobarvati s k barvami (ali z drugimi besedami povedano, tako da je graf G k-barvljiv). Zgled 5.6. Graf na sliki 5.14 je 2-barvljiv, če vozliščem 1, 3 in 5 priredimo barvo 1, vozliščema 2 in 4 pa barvo 2. Ta graf seveda ni 1-barvljiv. To pomeni, da je kromatično število enako 2. ♦ 1 2 3 5 4 Slika 5.14: Graf s 5 vozlišči. 5.4 Barvanje grafov 5-22 Definicija 5.3. Graf je ravninski ( planar), če in samo če ga lahko narišemo v eni ravnini, tako da se nobeni dve povezavi ne sekata. Vsak zemljevid je mogoče pobarvati s 4-barvami, tako da nobeni sosednji regiji nimata iste barve. Zemljevid transformiramo v graf, pri čemer vsaki regiji priredimo vozlišče, vsaki meji med regijami pa povezavo. Slika 5.15 kaže zemljevid s 5 regijami, tvorbo grafa v zemljevidu in posebej narisan graf. Dani zemljevid zahteva 4 barve. Slika 5.15: a) Zemljevid s 5 regijami, b) Tvorba grafa v zemljevidu, c) Samostojno narisan graf istega zemljevida. Velja naslednji teorem: Izrek 5.1. Vsak ravninski graf lahko pobarvamo z največ 4 barvami, tako da noben sosed nima enake barve. 5-23 5.4 Barvanje grafov Slika 5.16 kaže primer neravninskega grafa s 5 vozlišči. To je tudi neravninski graf z najmanj vozlišči. V osnovi je to polni graf. Polni graf s 4 vozlišči je ravninski graf. 1 3 2 4 5 Slika 5.16: Neravninski graf s 5 vozlišči. Lotili se bomo problema, kako pobarvati dani graf z m barvami. Seveda bomo poiskali vse možne načine barvanja. Graf G je podan z Boolovo matriko povezav. Če med vozliščema i in j obstaja povezava, je c[i, j] = T , če med njima povezave ni, je c[i, j] = F . Barve predstavimo s celimi števili 1, 2, . . . , m in rešitev je v obliki vektorja x = [x[1] x[2] . . . x[n]], kjer je x[i] barva i-tega vozlišča (x[i] ∈ {1, 2, . . . , m}). 5.4 Barvanje grafov 5-24 Uporabimo rekurzivno formulacijo sestopanja. Drevo prostora stanj je stopnje m in višine n. Vsako vozlišče na nivoju i ima m sinov, kar ustreza m možnim dodelitvam k x[i] (i = 1, 2, . . . , n). Zapišimo psevdokod procedure BARVANJE-GRAFA na globini k, ko predpostavljamo, da so barve vozliščem 1, 2, . . . , k −1 že določene. BARVANJE-GRAFA(n, c, m, k, x,rešitev) 1 loop % tvori vse legalne prireditve za x[k] 2 NOVA-BARVA(n, c, m, k, x) % priredi x[k] legalno barvo 3 if x[k] = 0 4 then exit % vozlišča k ni več mogoče pobarvati 5 if k = n 6 then rešitev ← rešitev ∪ x % vključi tekočo rešitev x % v množico rešitev 7 else BARVANJE-GRAFA(n, c, m, k + 1, x,rešitev) % sestopimo Procedura NOVA-BARVA določi novo barvo vozlišču k, tako da je ta različna od barv že pobarvanih sosednjih vozlišč. Nova barva x[k] je lahko katerakoli barva (število) v zaprtem intervalu [1, m]. Če vozlišču k ne moremo določiti barve, postavimo 0 v x[k] . NOVA-BARVA(n, c, m, k, x) 1 loop 2 x[k] ← (x[k] + 1) mod (m + 1) % naslednja barva 3 if x[k] = 0 4 then exit % izčrpali smo vse barve % preverimo, če ima kateri od sosedov že barvo x[k] 5 j=1 6 while j ≤ n and not (c[k, j] and x[k] = x[j]) 7 do j ← j + 1 8 if j = n + 1 9 then exit % najdena nova barva Proceduro BARVANJE-GRAFA pokličemo s: for k ← 1 to n do x[k] ← 0 BARVANJE-GRAFA(n, c, m, 1, x,0) 5-25 5.4 Barvanje grafov Zgled 5.7. Slika 5.17 prikazuje preprosti graf s 4 vozlišči (n = 4). Dani graf želimo pobarvati z največ 3 barvami (m = 3). Slika 5.17: Graf s 4 vozlišči. Za dani graf lahko napišemo naslednjo F T T F c= F T T F Boolovo matriko povezav: F T T F F T T F 1. Začetni pogoji so: x[1] = x[2] = x[3] = x[4] = 0. 2. Prvi klic je BARVANJE-GRAFA(4, c, 3, 1, x,0) na globini 0. 3. Vstopimo v proceduro NOVA-BARVA(4, c, 3, 1, x). Najprej določimo: x[1] = (0 + 1) mod 4 = 1. Pogoj pri 1. if (x[1] 6= 0) ni izpolnjen, zato postavimo j = 1. Zanka while se izvede 4-krat, saj so izpolnjeni vsi pogoji: 1 ≤ 4 and not (F and x[1] = x[1]) = T ⇒ j = 2 2 ≤ 4 and not (T and x[1] 6= x[2]) = T ⇒ j = 3 3 ≤ 4 and not (F and x[1] 6= x[3]) = T ⇒ j = 4 4 ≤ 4 and not (T and x[1] 6= x[4]) = T ⇒ j = 5 Ker je pri 2. if izpolnjen pogoj (j = n + 1 ali 5=5), izstopimo iz procedure NOVA-BARVA. 4. Smo ponovno v proceduri BARVANJE-GRAFA v vrstici 3 na globini 0. Ker nista izpolnjena pogoja pri 1. if (x[1] 6= 0) in 2. if (k = 1 6= n = 4), sestopimo v globino 1 s klicem BARVANJE-GRAFA(4, c, 3, 2, x,0). 5-26 5.4 Barvanje grafov 5. Vstopimo v proceduro NOVA-BARVA(4, c, 3, 2, x). a) 1. iteracija zanke loop: Najprej določimo: x[2] = (0 + 1) mod 4 = 1. Pogoj pri 1. if (x[2] 6= 0) ni izpolnjen, zato postavimo j = 1. Zanka while se ne izvede niti enkrat, saj ni izpolnjen pogoj: 1 ≤ 4 and not (T and x[1] = x[1]) = F Ker pri 2. if ni izpolnjen pogoj (j = n + 1 ali 1 6= 5), končamo iteracijo zanke loop. b) 2. iteracija zanke loop: Najprej določimo: x[2] = (1 + 1) mod 4 = 2. Pogoj pri 1. if (x[2] 6= 0) ni izpolnjen, zato postavimo j = 1. Zanka while se izvede 4-krat, saj so izpolnjeni vsi pogoji: 1 ≤ 4 and not (T and x[2] 6= x[1]) = T ⇒ j = 2 2 ≤ 4 and not (F and x[2] = x[2]) = T ⇒ j = 3 3 ≤ 4 and not (T and x[2] 6= x[3]) = T ⇒ j = 4 4 ≤ 4 and not (F and x[2] 6= x[4]) = T ⇒ j = 5 Ker je pri 2. if izpolnjen pogoj (j = n + 1 ali 5=5), izstopimo iz procedure NOVA-BARVA. 6. Smo ponovno v proceduri BARVANJE-GRAFA v vrstici 3 na globini 1. Ker nista izpolnjena pogoja pri 1. if (x[2] 6= 0) in 2. if (k = 2 6= n = 4), sestopimo v globino 2 s klicem BARVANJE-GRAFA(4, c, 3, 3, x,0). 7. Vstopimo v proceduro NOVA-BARVA(4, c, 3, 3, x). Najprej določimo: x[3] = (0 + 1) mod 4 = 1. Pogoj pri 1. if (x[3] 6= 0) ni izpolnjen, zato postavimo j = 1. Zanka while se izvede 4-krat, saj so izpolnjeni vsi pogoji: 1 ≤ 4 and not (F and x[3] = x[1]) = T ⇒ j = 2 2 ≤ 4 and not (T and x[3] 6= x[2]) = T ⇒ j = 3 3 ≤ 4 and not (F and x[3] = x[3]) = T ⇒ j = 4 4 ≤ 4 and not (T and x[3] 6= x[4]) = T ⇒ j = 5 Ker je pri 2. if izpolnjen pogoj (j = n + 1 ali 5=5), izstopimo iz procedure NOVA-BARVA. 5-27 5.4 Barvanje grafov 8. Smo ponovno v proceduri BARVANJE-GRAFA v vrstici 3 na globini 2. Ker nista izpolnjena pogoja pri 1. if (x[1] 6= 0) in 2. if (k = 3 6= n = 4), sestopimo v globino 3 s klicem BARVANJE-GRAFA(4, c, 3, 4, x,0). 9. Vstopimo v proceduro NOVA-BARVA(4, c, 3, 4, x). a) 1. iteracija zanke loop: Najprej določimo: x[4] = (0 + 1) mod 4 = 1. Pogoj pri 1. if (x[4] 6= 0) ni izpolnjen, zato postavimo j = 1. Zanka while se ne izvede niti enkrat, saj ni izpolnjen pogoj: 1 ≤ 4 and not (T and x[4] = x[1]) = F Ker pri 2. if ni izpolnjen pogoj (j = n + 1 ali 1 6= 5), končamo iteracijo zanke loop. b) 2. iteracija zanke loop: Najprej določimo: x[4] = (1 + 1) mod 4 = 2. Pogoj pri 1. if (x[4] 6= 0) ni izpolnjen, zato postavimo j = 1. Zanka while se izvede 4-krat, saj so izpolnjeni vsi pogoji: 1 ≤ 4 and not (T and x[4] 6= x[1]) = T ⇒ j = 2 2 ≤ 4 and not (F and x[4] = x[2]) = T ⇒ j = 3 3 ≤ 4 and not (T and x[4] 6= x[3]) = T ⇒ j = 4 4 ≤ 4 and not (F and x[4] = x[4]) = T ⇒ j = 5 Ker je pri 2. if izpolnjen pogoj (j = n + 1 ali 5=5), izstopimo iz procedure NOVA-BARVA. 10. Smo ponovno v proceduri BARVANJE-GRAFA v vrstici 3 na globini 3. Ker ni izpolnjen pogoj pri 1. if (x[4] 6= 0), gremo do 2. if, kjer je pogoj izpolnjen (k = 4 6= n = 4), zato izpišemo prvo možno rešitev: [x[1] x[2] x[3] x[4]] = [1 2 1 2]. 11. Zopet se vrnemo na začetek procedure BARVANJE-GRAFA (naslednja iteracija zanke loop) v globini 3. Vstopimo v proceduro NOVA-BARVA(4, c, 3, 4, x). Najprej določimo: x[4] = (2 + 1) mod 4 = 3. Pogoj pri 1. if (x[4] 6= 0) ni izpolnjen, zato postavimo j = 1. Zanka while se izvede 4-krat, saj so izpolnjeni vsi pogoji. Ker je pri 2. if izpolnjen pogoj (j = n + 1 ali 5=5), izstopimo iz procedure NOVA-BARVA. 5-28 5.4 Barvanje grafov 12. Smo ponovno v proceduri BARVANJE-GRAFA v vrstici 3 na globini 3. Ker ni izpolnjen pogoj pri 1. if (x[4] 6= 0), gremo do 2. if, kjer je pogoj izpolnjen (k = 4 = n = 4), zato izpišemo drugo možno rešitev: [x[1] x[2] x[3] x[4]] = [1 2 1 3]. 13. Vrnemo se na začetek procedure BARVANJE-GRAFA (naslednja iteracija zanke loop) v globini 3. Vstopimo v proceduro NOVA-BARVA(4, c, 3,4, x). Najprej določimo: x[4] = (3 + 1) mod 4 = 0. Pogoj pri 1. if je izpolnjen (x[4] = 0), zato izstopimo iz procedure NOVABARVA, saj smo izčrpali vse barve. 14. Smo ponovno v proceduri BARVANJE-GRAFA v vrstici 3 na globini 3. Ker je izpolnjen pogoj pri 1. if (x[4] = 0), izstopimo iz procedure in se vrnemo na globino 2, da preiščemo še ostale možnosti za x[3]. Na ta način nadaljujemo, dokler ne poiščemo vseh možnih rešitev. Delovanje procedure BARVANJE-GRAFA lahko opišemo z drevesom stanj na sliki 5.18. Rešitve predstavljajo listi z najvišjim nivojem, tj. n. Vseh rešitev je 18, od tega je 6 rešitev z 2 barvama in 12 rešitev s 3 barvami. Rešitve z 2 barvama so označene s puščico. Za dani graf velja, da ima kromatično število 2. ♦ Slika 5.18: Drevo prostora stanj in vse možnosti barvanja z največ 3 barvami. 5-29 5.4 Barvanje grafov Časovna zahtevnost algoritma BARVANJE-GRAFA Zgornja meja časovne zahtevnosti je: T (n) = O(nmn ). Literatura Aho, A. V., Hopcroft, J. E., and Ullman, J. D. (1974). The Design and Analysis of Computer Algorithms. Addison-Wesley, Reading. Cormen, T. H., Leiserson, C. E., and Rivest, R. L. (2007). Introduction to Algorithms. Druga izdaja, MIT Press, Cambridge. Horowitz, E., Sahni, S., and Rajasekaran, S. (1998). Computer Algorithms. Computer Science Press, New York. Kleinberg, J. and Tardos, E. (2006). Algorithm Design. Parson Education, Inc., New York. Kononenko, I. (1996). Načrtovanje podatkovnih struktur in algoritmov. Fakulteta za računalništvo in informatiko, Ljubljana. Kozak, J. (1997). Podatkovne strukture in algoritmi. Društvo matematikov, fizikov in astronomov Slovenije, Ljubljana. Levitin, A. (2007). The Design and Analysis of Algorithms. Druga izdaja, Pearson Education, Inc., Boston. Manber, U. (1989). Introduction to Algorithms. A Creative Approach. AddisonWesley, Reading. Nilsson, N. J. (1980). Principles of Artificial Intelligence. Tioga. Sedgewick, R. (2003). Boston. Algorithms in Java. Third Edition. Addison-Wesley, Vilfan, B. (1998). Osnovni algoritmi. Fakulteta za računalništvo in informatiko, Ljubljana.
© Copyright 2024