nav_dugme codeBlog codeBlog
  • početna Početna stranica
  • Sačuvani članci Sačuvani članci
  • Članci
     (spisak)
  • Kontakt
Povratak na vrh stranice

Info & povezani članci Info o članku - dugme

Info

trejler_sat Datum objave: 20.02.2020.

trejler_dokument Jezici: C

trejler_teg_narandzasti Težina: 9/10

C
algoritam
strukture podataka
nizovi
dinamičko programiranje
optimizacija
teorija

Povezani članci

Metode za optimizaciju algoritamaKlase složenosti algoritama (O notacija)Strukture podatakaOperacije sa bitovima u programskom jeziku COperacije sa tekstualnim datotekama u programskim jezicima C i PythonPostfiksna notacija - kako računari računaju?Binarno stablo pretrageUvod u objektno orijentisano programiranjeUvod u relacione baze podataka i SQLIzbor prvog programskog jezikaGNU/Linux - 1. deo - Uvod
Svi članci
If the automobile had followed the same development cycle as the computer, a Rolls-Royce would today cost $100, get a million miles per gallon, and explode once a year, killing everyone inside.
Robert X. Cringely

Uvod u dinamičko programiranje

Facebook LinkedIn Twitter Viber WhatsApp E-mail
zoom_plus zoom_minus bookmark
početna > Članci > Teorija

Uvod

Dinamičko programiranje je metoda optimizacije algoritama koja podrazumeva: raščlanjivanje glavnog problema na potprobleme koji se ponavljaju, i (potom) - računanje i pamćenje međurešenja.

Potproblemi se rešavaju jednom, nakon čega se zapamćena međurešenja mogu koristiti kada god se za tim ukaže potreba.

Naravno, ne mogu se u svim problemima prepoznati potproblemi koji se ponavljaju, * ali, za probleme kod kojih to jeste moguće, u opštem smislu važi da imaju optimalnu podstrukturu, a sam proces zapisivanja izračunatih rešenja potproblema naziva se memoizacija.

* U nečem (sasvim očekivano) mora biti "začkoljica", jer inače bi dinamičko programiranje, još ranije, verovatno postalo osnovni metod za rešavanje većine problema u programiranju.

Upotrebom tehnika dinamičkog programiranja, znatno se smanjuje vremenska složenost algoritama (tipično, od eksponencijalne do polinomne), odnosno, u najpraktičnijem smislu: uz povećano memorijsko zauzeće, veoma primetno se smanjuje vreme izvršavanja programa.

Da bismo sve navedeno bolje razumeli, razmotrićemo jedan od najpoznatijih problema dinamičkog programiranja - problem pronalaženja najdužeg zajedničkog podniza (pri čemu ćemo prvo prikazati postupak rešavanja problema preko neefikasnog, "naivnog" algoritma, a potom ćemo demonstrirati prednosti upotrebe metoda dinamičkog programiranja).

Problem najdužeg zajedničkog podniza

Početni problem je sledeći: za dva niza, potrebno je pronaći dužinu najdužeg zajedničkog podniza i ispisati elemente koji čine takav podniz.

Ako za primer uzmemo dva niza celobrojnih vrednosti: a[] = { 4, 3, 1, 2, 1, 5, 8, 9 } i b[] = { 4, 7, 3, 2, 8, 1 } ....

Najduži zajednički podniz - naivno rešenje - korak 01
Slika 1. - Nizovi za koje se traži najduži zajednički podniz.

.... letimičnim pregledom (u ovakvom jednostavnom primeru), nije teško uvideti da rešenje predstavlja bilo koji od sledeća dva podniza: { 4, 3, 2, 8 } ili { 4, 3, 2, 1 } .

Naravno, to smo lako uvideli zato što je uzorak koji posmatramo vrlo mali, i zato što (kao ljudi) imamo određenu sposobnost neposrednog sagledavanja "šire slike" na uzorcima "ne-baš-velikog" obima, međutim, računari takve sposobnosti nemaju uopšte (čak ni u slučaju obrade izrazito malih nizova), a u slučaju obrade većih nizova (pri čemu niz ne mora biti 'prevelik'; dovoljno je da se sastoji od svega nekoliko desetina elemenata), ljudi takođe moraju pribeći drugačijoj metodi sagledavanja, koja je (manje-više), ista onakva kakvu računari moraju koristiti u bilo kojim okolnostima.

Naivno rešenje

Za prethodno navedeni problem sa dva niza, naivno rešenje (pojam poznat od ranije), može se izvesti na sledeći način ....

U prvom koraku, vrednost prvog elementa niza b (4), pretražuje se među elementima niza a:

Najduži zajednički podniz - naivno rešenje - korak 02
Slika 2. - Naivno rešenje - korak 1.

Prvo poklapanje pojavljuje se već na 1. poziciji:

Najduži zajednički podniz - naivno rešenje - korak 03
Slika 3. - Naivno rešenje - korak 2. - Pronađeno je prvo poklapanje (dužina NZP - 1).

Dužina najdužeg zajedničkog podniza (1), pamti se 'za kasnije', i potom se prelazi na sledeći element niza b.

U sledećem koraku, vrednost drugog (to jest, sledećeg) elementa niza b (7), traži se na pozicijama u nizu a koje slede posle pozicije na kojoj je pronađeno prvo poklapanje ....

Najduži zajednički podniz - naivno rešenje - korak 04
Slika 4. - Naivno rešenje - korak 3.

.... međutim, u ovom slučaju element 7 ne nalazi se ni na jednoj poziciji u nizu a.

Najduži zajednički podniz - naivno rešenje - korak 05
Slika 5. - Naivno rešenje - korak 4. - U ovom slučaju nema poklapanja.

Pretraga se usmerava na sledeći element niza b (3) ....

Najduži zajednički podniz - naivno rešenje - korak 06
Slika 6. - Naivno rešenje - korak 5.

.... koji se poklapa sa 2. elementom niza a.

Najduži zajednički podniz - naivno rešenje - korak 07
Slika 7. - Naivno rešenje - korak 6. - Pronađeno je poklapanje (dužina NZP - 2).

Pamti se nova najveća (pronađena) dužina najdužeg zajedničkog podniza (2) i potom se prelazi na sledeći element niza b, i (naravno), sličan postupak se ponavlja, sve dok se ne pronađe podniz "najveće dužine" ....

Četvrti element niza b (2) ....

Najduži zajednički podniz - naivno rešenje - korak 08
Slika 8. - Naivno rešenje - korak 7.

.... poklapa se sa 4. elementom niza a (dužina najdužeg zajedničkog podniza je 3).

Najduži zajednički podniz - naivno rešenje - korak 09
Slika 9. - Naivno rešenje - korak 8. - Pronađeno je poklapanje (dužina NZP - 3).

Sledeći element niza b (8) ....

Najduži zajednički podniz - naivno rešenje - korak 10
Slika 10. - Naivno rešenje - korak 9.

.... poklapa se sa 7. elementom niza a (dužina najdužeg zajedničkog podniza je 4).

Najduži zajednički podniz - naivno rešenje - korak 11
Slika 11. - Naivno rešenje - korak 10. - Pronađeno je poklapanje (dužina NZP - 4).

Poslednji element niza b (1) ....

Najduži zajednički podniz - naivno rešenje - korak 12
Slika 12. - Naivno rešenje - korak 11.

.... ne poklapa se ni sa jednim elementom niza a (koji sledi posle pozicije na kojoj je pronađeno poslednje poklapanje) ....

Najduži zajednički podniz - naivno rešenje - korak 13
Slika 13. - Naivno rešenje - korak 12. - Nema poklapanja.

.... i stoga je najduži zajednički podniz ('za koji trenutno znamo') - podniz koji je pronađen u pretposlednjem koraku pretrage, a dužina tog podniza je 4:

Najduži zajednički podniz - naivno rešenje - korak 14
Slika 14. - Naivno rešenje - konačni rezultat prvog prolaska - dužina NZP-a je 4, ali - u pitanju je samo prvi NZP koji je pronađen - i takav niz ne mora predstavljati konačno rešenje!

Kratka analiza

Iako na prvi pogled može delovati da smo došli do zadovoljavajućeg rešenja, prikazani postupak ima nekoliko očiglednih nedostatka, od kojih je najbitniji sledeći: uvek postoji mogućnost da (prvi) podniz koji je pronađen - uopšte nije najduži zajednički podniz?!

U gornjem primeru jeste - tako smo udesili zarad jednostavnosti i preglednosti; u nekom drugom slučaju, "najduži" podniz koji se pronađe u prvom prolasku, nikako ne mora biti najduži mogući !

Da li prvi pronađeni najduži podniz, jeste i najduži mogući - moguće je ustanoviti tek pošto se pronađu i ispitaju svi zajednički podnizovi (u sledećoj "etapi", "jednoj od mnogih", ponovo bi bilo potrebno porediti sledbenike iz niza b sa sledbenicima iz niza a, koji dolaze posle elemenata koji su se poklopili u prvom prolasku (npr. u prvom sledećem poređenju, u obzir se uzimaju elementi b[2] i a[1], nakon čega se porede elementi b[2] i a[2], a posle toga slede i ostala poređenja)).

Prosto rečeno, navedeni postupak "ume da potraje" (u pitanju je algoritam eksponencijalne složenosti), međutim, postoji i drugi problem: posle svih ('ne-baš-malobrojnih') radnji, znali bismo samo dužinu * najdužeg podniza, ali, ne bismo imali zabeležene elemente koji čine podniz.

* U pojedinim situacijama, dovoljno je pronaći samo dužinu najdužeg zajedničkog podniza, ali, shodno 'propozicijama' koje smo naveli na početku članka, potrebno je pronaći: ne samo dužinu najdužeg zajedničkog podniza, već i listu elemenata koji čine najduži zajednički podniz.

Budući da je potrebno iznaći postupak preko koga se pronalazi i spisak elemenata koji čine najduži zajednički podniz, a preko postupka koji smo prethodno prikazali - uspeli smo da pronađemo samo dužinu prvog "najdužeg" zajedničkog podniza, pri čemu su zanemareni ostali "potencijalni" najduži zajednički podnizovi (setimo se da u konkretnom primeru postoji i podniz 4, 3, 2, 1, iste dužine, a u drugim primerima može biti i mnogo više od dva podniza koji zadovoljavaju uslov zadatka) - jasno je da moramo "tražiti dalje" ....

Rešenje korišćenjem metoda dinamičkog programiranja.

Problemi koji su opisani na kraju prethodnog poglavlja mogu se rešiti korišćenjem metoda dinamičkog programiranja, što (da se podsetimo), podrazumeva zapisivanje rešenja potproblema i korišćenje zapisanih (među)rešenja - nasuprot ponovnom računanju (koje je "vremenski skupo", odnosno dugotrajno).

Međutim, prvo je potrebno prepoznati da li u određenom problemu (uopšte) postoji "optimalna podstruktura", tj. da li postoje "potproblemi koji se ponavljaju".

U slučaju problema najdužeg zajedničkog podniza, optimalna podstruktura ogleda se u sledećem: za svaku kombinaciju pozicija unutar niski a i b, moguće je odrediti - i zapisati - dužinu najdužeg zajedničkog podniza koji odgovara kombinaciji (i moguće je, po potrebi, očitati konkretne znakove koji tvore takav niz).

Što se tiče "tehnikalija" tj. struktura podataka koje su neophodne za rešavanje problema, za početak * je potrebno kreirati matricu čija su polja popunjena nulama i čiji broj vrsta (tj. redova) odgovara broju elemenata kraćeg niza, a broj kolona odgovara broju elemenata dužeg niza (s tim da ćemo obe dimenzije uvećati za 1 - videćemo u nastavku zašto).

* U nastavku, potrebno je i popuniti matricu (odgovarajućim podacima). :)

Zarad bolje preglednosti, elemente nizova a i b ćemo ovoga puta zameniti znakovima alfabeta koji odgovaraju brojevima koje smo u prethodnom razmatranju koristili, i stoga nizovi (koji su praktično postali niske, odnosno stringovi), sada imaju sledeću strukturu ....

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 1
Slika 15. - Nizovi za koje se traži NZP - metodom dinamičkog programiranja (ovoga puta, koristićemo nizove znakova).

.... a matrica koja se koristi za beleženje međurešenja, ima sledeći oblik i početno stanje (uz napomenu da su tamno siva polja sa znakovima iz niski dodata samo zarad preglednosti (tj. "efekta"), i ne postoje u implementaciji): *

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 2
Slika 16. - Pomoćna matrica - početno stanje (u implementaciji, potrebno je da sva polja budu inicijalizovana vrednošću 0, što nije prikazano na slici, zarad preglednosti).

I ovoga puta postoje pojedinačni koraci koji se tiču direktnog poređenja znakova, ** ali, sa jednom (velikom) razlikom - nema ponovnog ispitivanja za pozicije koje su već ispitane!

* Takođe (kao što smo ranije nagovestili), i ostala polja matrice potrebno je popuniti nulama, ali, to nismo prikazivali na slikama, zarad bolje preglednosti.

** Direktno poređenje - teško se može izbeći u ovakvom algoritmu. :)

Međutim, umesto ponovnog računanja, koriste se zapamćeni rezultati prethodnih ispitivanja.

Počinjemo sa pretragom.

Prvi element niza b poklapa se sa prvim elementom niza a ....

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 3
Slika 17. - Prvi element niza b poredi se sa prvim elementom niza a.

.... što će biti uredno zabeleženo u odgovarajuće polje matrice:

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 4
Slika 18. - Algoritam pronalazi poklapanje, a odgovarajuća vrednost (koja predstavlja broj 'dotadašnjih poklapanja'), upisuje se u pomoćnu matricu.

Usputna napomena: iako na nivou 'programerske intuicije' deluje da je sve u redu sa upisanom vrednošću (budući da vrednost 1 'ima smisla za prvo poklapanje'), ne sumnjamo da ste se odmah zapitali šta broj 1 zapravo predstavlja u konkretnom slučaju (tj. zašto i kako je izabrana 'baš' vrednost 1, a ne npr. 143, 216 i sl)?!

Za sada ćemo samo poverovati intuiciji (i nećemo širiti diskusiju dok se ne upoznamo sa još nekolicinom 'uvodnih detalja'), ali, ubrzo ćemo se osvrnuti na pravi smisao vrednosti 1 (tj. uopšteno, na smisao različitih vrednosti koje se upisuju u polja matrice).

Što se tiče prvog poklapanja, u sve naredne pozicije u prvom redu matrice, takođe se može preneti vrednost 1.

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 5
Slika 19. - Vrednost 1 prenosi se u ostatak reda (u nastavku teksta, pojasnićemo kako tačno se obavlja prenos).

Prenete jedinice imaju sledeće značenje: kada pogledamo bilo koji element niza a - posle drugog elementa, i prvi element niza b, najduži zajednički podstring ima dužinu jedan.

Kao što smo nagovestili, usput ćemo se upoznavati sa raznim detaljima, a nakon što popunimo celu matricu, objasnićemo i ("pravi") algoritam.

Pretraga se nastavlja ....

U obzir se uzima sledeći element niza b, to jest, znak 'g' ....

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 6
Slika 20. - Drugi element niza b poredi se sa elementima niza a, ali, nema nijednog poklapanja.

.... ali, pošto ne postoji (nijedno) poklapanje, u polja matrice direktno se prenose vrednosti iz gornjeg reda.

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 7
Slika 21. - Budući da u poslednjem koraku pretrage nije pronađeno nijedno poklapanje, u ostala polja u redu, prenose se vrednosti iz gornjeg reda.

Kako se tačno obavlja prenos u ovakvoj situaciji (kada na obradu dospe prvi znak iz drugog reda)? Posmatra se vrednost u gornjem polju (u ovom slučaju 1), vrednost u levom polju (u ovom slučaju 0), i bira se i prenosi veća od dve vrednosti.

I ovoga puta, jedinice u 'drugom' redu ne znače da se znak 'g' poklapa sa nekim od znakova iz niske a (jer je očigledno da poklapanja nema), već, praktično, jedinice u drugom redu sugerišu da "negde", "iza", postoji poklapanje dužine 1 (ili, još praktičnije: sve do kraja drugog reda, kroz matricu se "provlači" poklapanje b[0] == a[0], prvo koje je pronađeno i zabeleženo).

U sledećem koraku, ispituje se poklapanje trećeg elementa niza b (znak 'c'), sa elementima niza a:

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 8
Slika 22. - Treći element niza b poredi se sa elementima niza a, pri čemu se pojavljuje poklapanje na 2. mestu.

Pošto je znak 'c' pronađen na 2. poziciji u nizu a, "deluje" kao da bi trebalo upisati vrednost 2 u obeleženo polje matrice, međutim - kako to rešiti algoritamski (to jest, kako naći "opravdanje")?

Na ovom mestu, vraćamo se na pitanje koje smo postavili kada je prva jedinica upisana u matricu ....

Broj prethodnih (tj. "dotadašnjih") poklapanja, zapisan je u polju matrice koje se nalazi (jedno mesto) gore-levo u odnosu na polje u koje treba ubeležiti informaciju o trenutnom poklapanju.

U konkretnom primeru, polje "gore-levo" sadrži vrednost 1.

Pronađenu vrednost samo treba uvećati za 1, to jest, treba - "baš kao što je delovalo" - upisati vrednost 2 (u polje koje se tiče trenutnog poklapanja).

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 9
Slika 23. - Zarad pronalaženja vrednost za upis (u situaciji kada je pronađeno poklapanje), potrebno je: osvrnuti se na polje koje se nalazi dijagonalno (levo-gore), i upisati vrednost koja je veća za 1 od pronađene vrednosti.

Već posle nekoliko koraka možemo videti 'lepotu i smisao' dinamičkog programiranja na delu: ne moraju se ponovo 'prebrojavati poklapanja' za prethodne korake (koji, da se podsetimo, praktično predstavljaju potprobleme).

Rešenja za prethodne korake - već su izračunata i zapisana.

Na ovom mestu takođe vidimo i razlog zašto se 'gabariti' matrice uvećavaju (još na početku), za 1 red i 1 kolonu.

Ako se vratimo na prvo poklapanje koje je pronađeno (b[0] == a[0]), jasno je da za navedeno poklapanje takođe mora postojati odgovarajuće polje matrice u kome je zapisan broj 'dotadašnjih' poklapanja i, u navedenom kontekstu, ako matricu označimo sa m i usmerimo se na polje matrice m[1][1] (koje se odnosi na poklapanje b[0] == a[0]), broj prethodnih poklapanja zapisan je u polju m[0][0].

(Naravno, isti princip važi i za ostala poklapanja iz drugog reda i druge kolone).

Drugo pitanje je: kako možemo znati (u ovom slučaju), da se dvojka sme preneti u ostala polja (u redu)?

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 10
Slika 24. - Ostatak reda takođe se popunjava vrednošću 2.

Jednostavno: znak 'c' se ne pojavljuje ni na jednoj od sledećih pozicija u nizu a. *

* To smo, za sada, utvrdili vizuelnom metodom, a pravi algoritam prenosa biće prikazan na kraju članka (kao što smo već naveli), i što je najlepše od svega - zapravo je prilično jednostavan. :)

Sledeći znak koji se poredi je znak 'b':

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 11
Slika 25. - Četvrti element niza b poredi se sa elementima niza a, pri čemu se pojavljuje poklapanje na 4. mestu.

Pronađeno je poklapanje sa 4. znakom niza a i, po istom algoritmu koji je korišćen u prethodnim koracima: u obzir se uzima vrednost iz gornjeg levog polja, pronađena vrednost uvećava se za jedan, a rezultat se upisuje u odgovarajuće polje matrice (pri čemu se broj 3 prenosi i u ostala polja u redu).

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 12
Slika 26. - Vrednost za upis je 3 (i ovoga puta, vrednost se prenosi u ostatak reda).

U sledećem koraku, znak 'h' traži se među elementima niza a:

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 13
Slika 27. - Peti element niza b poredi se sa elementima niza a, pri čemu se pojavljuje poklapanje na pretposlednjem mestu.

Znak 'h' iz niza b, poklapa se sa 7. elementom niza a (i stoga se u odgovarajuće polje matrice beleži vrednost 4, koja se takođe prenosi i u ostatak reda).

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 14
Slika 28. - Vrednost za upis je 4 (i ovoga puta, vrednost se prenosi u ostatak reda).

Na kraju, susrećemo se i sa složenijom situacijom u kojoj se znak iz niske b dvaput pojavljuje u niski a.

Recimo da takva situacija može biti pomalo zbunjujuća pri prvom susretu i stoga zaslužuje dodatnu pažnju.

Znak 'a', prvi put se u nizu a pojavljuje na 3. mestu:

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 15
Slika 29. - Poslednji element niza b poredi se sa elementima niza a (pri čemu se prvo poklapanje pojavljuje na 3. mestu).

Shodno ranije utvrđenim pravilima, u odgovarajuće polje matrice uredno će biti ubeležena vrednost 3 (pri čemu ubeležena vrednost praktično predstavlja podniz 'd', 'c', 'a'):

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 16
Slika 30. - Vrednost za upis je 3, ali, ovoga puta vrednost se prenosi samo do prvog sledećeg mesta na kome dolazi do poklapanja (uskoro ćemo se detaljno upoznati sa univerzalnim algoritmom, koji precizno definiše pravila za 'prenos').

Sledeća pojava znaka 'a' je na 5. mestu:

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 17
Slika 31. - Sledeće poklapanje pojavljuje se na 5. poziciji u nizu a.

U polje matrice (koje odgovara poklapanju), beleži se vrednost 4 ....

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 18
Slika 32. - Vrednost za upis je 4 (ovoga puta, vrednost se prenosi u ostatak reda).

.... i vidimo da pojava prvog znaka 'a' u nizu a - ni na koji način nije poremetila algoritam.

Hoćemo reći: poslednje poklapanje ('d', 'c', 'b', 'a'), zapravo nije u ("prevelikoj") vezi sa poklapanjem koje je pronađeno u prethodnom koraku.

Za svako od poklapanja u poslednjem redu, postoji "objašnjenje i pokriće" (i podaci zabeleženi u okolnim poljima matrice).

Nedoumice se otklanjaju lako, a moguće je pronaći i pojedinačna poklapanja (koja odgovaraju upisanoj dužini podniske).

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 19
Slika 33. - Matrica je popunjena, a dužina najdužeg zajedničkog podniza, upisana je u donje desno polje matrice

U svakom slučaju, matrica je sada 'kompletirana'.

Pronalaženje pozicija

U donjem desnom polju matrice upisana je vrednost koja predstavlja dužinu najdužeg zajedničkog podniza, ali, ta informacija, sama po sebi, ne ukazuje na konkretne pozicije na kojima se nizovi poklapaju, međutim ('srećom'), pozicije su već upisane u matricu (na donekle posredan način) - i potrebno je samo pronaći ih (obilaskom matrice 'unazad').

Zarad pronalaženja polja u kome je zabeleženo prvo poklapanje dužine 4, potrebno je prvo (krećući se od donjeg desnog polja matrice nagore), pronaći prvi red u kome se pojavljuje vrednost 4 (u primeru koji koristimo, vrednost 4 pojavljuje se u pretposlednjem redu).

Potom, "kretanjem ulevo", pronalazi se i kolona, odnosno - konkretno polje, u kome se vrednost 4 prvi put pojavljuje ("prva četvorka" označena je na slici zelenom bojom).

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 20
Slika 34. - Pronalaženje polja u kome je zabeleženo prvo poklapanje dužine 4.

Za pronalaženje 'prve trojke', treba preći sa polja koje sadrži 'prvu četvorku', na polje koje se nalazi jedno mesto gore i jedno mesto levo (trojka sa kružićem na donjoj slici), i potom se sa tog polja traži prva trojka - na isti način kako je pronađena 'prva četvorka':

  • prvo je potrebno, 'krećući se nagore', pronaći prvi red u kome se trojka pojavljuje (program uvek mora pokušati da pređe u gornji red, ali, ovoga puta ostaje u istom redu)
  • nakon pronalaženja odgovarajućeg reda, "kretanjem ulevo" pronalazi se i odgovarajuća kolona
Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 21
Slika 35. - Pronalaženje polja u kome je zabeleženo prvo poklapanje dužine 3.

Postupak se ponavlja, sve dok se ne pronađu i "prva dvojka" i "prva jedinica" (sve pozicije na kojima se prvi put pojavljuju poklapanja, označene su na slici).

Najduži zajednički podniz - rešenje metodom dinamičkog programiranja - korak 22
Slika 36. - Pronalaženje ostalih poklapanja.

Algoritam za upis vrednosti u polja matrice

U glavnom primeru koji smo prikazali, vrednosti su posle poklapanja "nekako" prenošene u sva polja do kraja reda (s tim da smo pojasnili zašto u poslednjem redu prvo poklapanje nije odmah preneto i u ostala polja).

Nismo vas nigde 'prevarili' (niti je upisivanje vršeno nasumično), ali, detaljno objašnjenje o tome kako prenos funkcioniše, ipak smo ostavili za sam kraj, i (kao što smo ranije naveli), postupak ni izdaleka nije komplikovan. :)

Elementi nizova koji se porede, poklapaju se, ili se ne poklapaju:

  • ako se elementi poklapaju, u trenutno polje upisuje se vrednost koja je za 1 veća od vrednosti iz 'gornjeg-levog' polja pomoćne matrice (tj. iz polja m[i - 1][j - 1])
  • ako se elementi nizova ne poklapaju, potrebno je sagledati 'susedne vrednosti' koje se u matrici nalaze: jedno polje iznad i jedno polje levo (u odnosu na trenutno polje), nakon čega se upisuje veća od dve vrednosti
		
// a - duži niz, čija dužina odgovara broju kolona
// b - kraći niz, čija dužina odgovara broju redova
// m - pomoćna matrica
// i - brojač koji se poklapa sa nizom b
//     (tj. sa redovima matrice)
// j - brojač koji se poklapa sa nizom a
//     (tj. sa kolonama matrice)
						
// Ako se dva elementa unutar
// nizova poklapaju ....

if (b[i - 1] == a[j - 1]) {
	m[i][j] = m[i - 1][j - 1] + 1;
	
	// .... u matricu se upisuje 
	// vrednost koja je za jedan veća od
	// vrednosti iz 'gornjeg levog' polja,
	// a ako se elementi ne poklapaju ....
else {
	// Posmatraju se: levo polje (m[i][j - 1])
	// i gornje polje polje matrice (m[i - 1][j]),
	// i bira se veća od dve vrednosti
	// (obično je gornja vrednost veća)
	
	m[i][j] = (m[i][j - 1] >= m[i - 1][j])?
	           m[i][j - 1] :
	           m[i - 1][j];
}
		
	
Slika 37. - Algoritam za upisivanje vrednosti u polja pomoćne matrice.

Prikazani postupak se (naravno) ponavlja za svako polje, i (u praktičnom smislu), daje iste rezultate koje smo prikazali u glavnom primeru koji smo razmatrali.

Čitaocima koji su skloni "avanturizmu", prepuštamo (za vežbu), da samostalno osmisle algoritam koji ispisuje sve najduže zajedničke podnizove! :)

Autor članka Nikola Vukićević Za web portal codeblog.rs
Napomena: Tekstovi, slike, web aplikacije i svi ostali sadržaji na sajtu codeblog.rs (osim u slučajevima gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog pismenog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook LinkedIn Twitter Viber WhatsApp E-mail
početna > Članci > Uvod u dinamičko programiranje
codeBlog codeBlog
Sajt posvećen popularizaciji kulture i veštine programiranja.
Napomena: Tekstovi i slike na sajtu codeblog.rs (osim u slučajevima, gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook - logo
Instagram - logo
LinkedIn - logo
Twitter - logo
E-mail
Naslovna
   •
Uslovi korišćenja
   •
Obaveštenja
   •
FAQ
   •
Kontakt