Sunteți pe pagina 1din 4

Tehnica Greedy

(Adugtor la punctul 2.3. (pag. 32) din manualul pentru clasa 11 INFORMATICA. Tehnici de programare.[1])

Este foarte dificil de a scrie forma general a unei probleme rezolva folosind tehnica Greedy. S considerm o mulime A cu n elemente. Se cere o submulime a sa cu m elemente (n cazul m=n este important ordinea alegerii elementelor), astfel nct s fie ndeplinite anumite condiii (acestea difer de la o problem la alta). Exemplu: se consider o mulime de n numere reale. Se cere o submulime a sa, astfel nct suma elementelor sale s fie maxim. Pentru rezolvare, vom alege un prim element al mulimii de numere reale. Dac este posibil, acesta va fi adugat soluiei, iniial vide. Posibilitatea ca acesta s fie adugat este dat de semnul numrului (acesta trebuie s fie mai mare ca O). Se alege un al doilea numr, cu care se procedeaz n mod asemntor. Algoritmul se ncheie cnd au fost alese l eventual adugate toate elementele mulimii. Pentru a rezolva o problem cu Greedy, soluia se construiete, dup regula: Pentru fiecare element care urmeaz s fie adugat soluiei finale, se efectueaz o alegere a sa din elementele mulimii A (dup un mecanism specific fiecrei probleme n parte), iar dac este posibil, acesta este adugat. Algoritmul se termin fie cnd a fost gsit soluia cerut, fie cnd s-a constatat inexistena acesteia. Intuitiv, alegem un element, al doilea,....pn cnd obinem ce dorim sau pn cnd au fost testate toate elementele mulimii. De aici provine si numele metodei (greedy=lacom). Greedy pare att de simpl nct, la nceput, ne mir faptul c a fost evideniat ca tehnic. La o analiz atent, vom observa c lucrurile nu stau chiar aa. Exemplul prezentat este didactic (l rezolvam i fr s tim c exist aceast tehnic), el nu are alt rol dect de a evidenia caracteristicile tehnicii. Tehnica Greedy poate fi privita ca o particularizare a tehnicii Backtracking, n care se renuna la mecanismul de ntoarcere. S analizm n paralel, cele dou tehnici, pentru a putea stabili asemnrile i diferenele existente ntre ele: => ambele tehnici ofer soluii sub form de vector; => tehnica Backtracking poate oferi toate soluiile problemei, n timp ce tehnica Greedy ofer o singur soluie => tehnica Greedy nu dispune de mecanismul ntoarcerii, specific tehnicii Backtracking. : Aceasta este diferena esenial dintre cele doua tehnici, diferen care are consecine uriae n ce privete aplicabilitatea lor. Consecina 1. Este necesar ca cel care elaboreaz un algoritm Greedy s tie faptul ca, procednd n modul ales de el, ajunge la rezultatul dorit. Pentru fiecare problem n parte, dup ce se identifica un algoritm, este obligatoriu s se demonstreze c acesta conduce la soluia optima. Demonstraia faptului ca se ajunge la soluia optim este specific fiecrei probleme n parte. Consecina 2. Tehnica Greedy conduce la timp de calcul polinomial. Motivul care conduce la acest timp de calcul, tine de mecanismul tehnicii. S presupunem c mulimea din care se face alegerea are n elemente si c soluia are tot n elemente (caz maxim). Se fac n alegeri, la fiecare alegere se fac n teste, rezulta un algoritm cu timp O(n2). De multe ori, este necesar ca elementele mulimii. A s fie sortate, pentru ca apoi s alegem din acestea, iar sortarea necesita un timp minim O(n x log2n). Ins sortarea se efectueaz la nceput. Prin urmare, acest timp se adun, deci nu influeneaz rezultatul. 0 ntrebare fireasc: fiind dat o problem, exist ntotdeauna un algoritm de tip Greedy care gsete soluia optim? Evident, NU. Exist probleme pentru care nu se cunosc astfel de algoritmi. Mai mult, pentru cele mai multe probleme nu se cunosc algoritmi Greedy. Avantajul timpului polinomial, conduce la necesitatea utilizrii tehnicii Greedy. Din alt punct de vedere, nu tuturor problemelor li se pot aplica algoritmi de acest tip. Ce este de fcut? => Pentru problemele pentru care nu se cunosc algoritmi care necesit timp polinomial, se caut soluii, chiar dac nu obine, dar apropiate de acestea, dar care au fost obinute n timp util. Multe din aceste soluii sunt obinute cu Greedy. Astfel de algoritmi se numesc algoritmi euristici. n continuare, vom da mai multe exemple de probleme care se rezolv cu Greedy.
Pagina 1 din 4

Probleme pentru care Greedy obine soluia optim Problema banilor (Problema nr. 7, testul 3 Bacalaureat 2002.)
Scriei un program, care afieaz modalitatea de plat, folosind un numr minim de bancnote, a unei sume ntregi S de lei (S<20000). Plata se efectueaz folosind bancnote cu valoarea 1, 5, 10, 50, 100, 200 i 500 de lei. Numrul de bancnote de fiecare valoare se citete din fiierul text BANI.IN, care conine 7 rnduri, n fiecare din care sunt indicate numrul de bancnote respectiv de 1, 5, 10, 50, 100, 200 i 500 de lei. Intrare: Fiierul text BANI.IN i de la tastatur se citete suma S. Ieire: Dac e posibil de pltit aceast sum S, atunci la ecran se va afia valoarea bancnotei i numrul de bancnote respective utilizate la plat. Dac bancnote de careva valoare nu se folosesc, atunci nu se afieaz aceast valoare. Dac nu este posibil de efectuat plata cu bancnotele indicate afiai mesajul respectiv. Menionm, c probleme asemntoare, cu banii, sunt mai multe. De obicei se presupune c bancnote de fiecare fel avem orict de multe. Aceast problem ne limiteaz numrul de bancnote. Ideea algoritmului de rezolvare a aceste probleme const n faptul c trebuie s ncepem eliberarea restului de la cea mai mare bancnot. Exist 2 variante, dac suma necesar e mai mare ca produsul dintre numrul de bancnote i nominalul atunci se iau toate bancnotele de acest nominal, dac nu atunci se iau attea bancnote, cte ncap, care se afl prin mprirea sumei rmase la nominal. Pentru rezolvare se folosete un tablou cu 3 rnduri i 7 coloane (pentru fiecare nominal cte o coloan). n primul rnd al tabloului vom pstra nominalul bancnotelor, n al doilea rnd - numrul bancnotelor citite din fiier i n al treilea rnd - numrul bancnotelor obinute la schimb, practice ceea ce aflm. Calculul se va ncepe cu coloana a 7, adic ncepem de la sfrit.
Program V3P7_02; type tablou=array[1..3,1..7] of integer; var s,ss,i : integer; a:tablou; f:text; {In primul rind al tabelului vom pastra nominalul bancnotelor} {In al doilea rind - numarul bancnotelor citite din fisier} {In al treilea rind - numarul bancnotelor obtinute la schimb} Procedure Afisare(sa:integer); begin writeln('suma ',s); if sa<>0 then writeln('nu poate fi transformata cu bancnotele date ') else begin writeln('se plateste cu urmatoarele bancnote'); for i:=1 to 7 do if a[3,i]<>0 then writeln('bancnote de ',a[1,i]:6,' sau folosit ',a[3,i]); end end; { Afisare } Procedure calcul(var sa:integer); var nb:integer; begin i:=7; while (i>=1) and (sa>0) do begin nb:=sa div a[1,i]; if nb<>0 then if nb>= a[2,i] then a[3,i]:=a[2,i] else a[3,i]:=nb; sa:=sa-a[3,i]*a[1,i]; i:=i-1; end; end; { calcul } begin a[1,1]:=1; a[1,2]:=5; a[1,3]:=10; a[1,4]:=50; a[1,5]:=100; a[1,6]:=200; a[1,7]:=500; assign (f,'bani.in'); reset(f); for i:=1 to 7 do readln(f,a[2,i]); write ('introduceti suma de lei S ');readln(s); ss:=s; calcul(ss); Afisare(ss); end. Pagina 2 din 4

Problema rucsacului (nr. 6, pag. 35 [1])


O persoan are un rucsac cu care poate transporta o greutate maxim G. Persoana are la dispoziie n obiecte si cunoate pentru fiecare obiect greutatea si ctigul care se obine n urma transportului su la destinaie. Se cere s se precizeze ce obiecte trebuie s transporte persoana n aa fel nct ctigul sa fie maxim. O precizare n plus transform aceast problema n alte dou probleme distincte. Aceast precizare se refer la faptul c obiectele pot fi sau nu tiate pentru transportul la destinaie. In prima situaie, problema poart numele de problema continu a rucsacului, iar n a doua avem problema discreta a rucsacului. Aceste dou probleme se rezolv diferit Varianta continu a problemei rucsacului este rezolvat mai jos, iar cea discret se rezolv cu ajutorul programrii dinamice. Problema continu a rucsacului, n care persoana are posibilitatea s taie obiectele. n acest fel, se poate obine o ncrcare mai eficient a rucsacului. Algoritmul este urmtorul: se calculeaz, pentru fiecare obiect n parte, eficiena de transport rezultat prin mprirea ctigului la greutate (de fapt, acesta reprezint ctigul obinut prin transportul unitii de greutate); obiectele se sorteaz n ordine descresctoare a eficienei de transport si se preiau n calcul n aceast ordine; ctigul iniial va fi 0, iar greutatea rmas de ncrcat va fi greutatea rucsacului; att timp ct nu a fost completat greutatea maxim a rucsacului si nu au fost luate in considerare toate obiectele, se procedeaz astfel: dintre obiectele nencrcate se selecteaz acela cu cea mai ridicat eficien de transport i avem dou posibiliti: acesta ncape n totalitate n rucsac, deci se scade din greutatea rmas de ncrcat greutatea obiectului, la ctig se cumuleaz ctigul datorat transportului acestui obiect; se tiprete 1, n sensul c ntregul obiect a fost ncrcat; obiectul nu ncape n totalitate n rucsac, caz n care se calculeaz ce parte din el poate fi transportat, se cumuleaz ctigul obinut cu transportul acestei pri din obiect, se tiprete procentul care s-a ncrcat din obiect, iar greutatea rmas de ncrcat devine 0. Vom considera un exemplu numeric. Greutatea care poate fi transportat cu ajutorul rucsacului aste 3 Avem la dispoziie 3 obiecte. Greutatea i ctigul pentru fiecare obiect sunt prezentate mai jos:

Eficiena de transport este 1 pentru primul obiect, 4 pentru al doilea si 2 pentru al treilea. In concluzie, obiectul 2 se ncarc n ntregime n rucsac, obinnd un ctig de 4 i rmne o capacitate de transport de dou uniti de greutate. Se ncarc 2/3 din obiectul 3 (care este al doilea n ordinea eficienei de transport) pentru care se obine ctigul 4. Ctigul obinut n total este 8. Se remarca strategia GREEDY prin alegerea obiectului care va fi transportat, alegere asupra creia nu se revine.
program rucsac; type tablou=array [1..4] of real; matrice=array [1..10] of tablou; {In prima coloana se inscrie costul, In a II - greutatea, in a III - eficienta, si in a IV - a cata parte se ia tabloul c il folosim la sortare, "al treilea pahar"} var a:matrice; c:tablou; f:text; loc,n,g,i,j:integer; max,castig,dg:real; begin assign (f,'rucsac.txt'); reset (f); readln(f,n,g); for i:=1 to n do begin readln(f,a[i,1],a[i,2]); a[i,3]:=a[i,1]/a[i,2]; a[i,4]:=0; end; {sortam tabloul dupa eficienta} Pagina 3 din 4

for i:=1 to n-1 do begin max:=a[i,3];loc:=i; for j:=i+1 to n do if a[j,3]>max then begin max:=a[j,3]; loc:=j; end; c:=a[i]; a[i]:=a[loc]; a[loc]:=c; end; {Aflam cat din fiecare obiect se pune in rucsac si calculam castigul} castig:=0; i:=1; dg:=g; writeln ('greutatea ','costul ','eficienta ','rucsac'); while (i<=n) and (dg>0) do begin; if dg>=a[i,2] then begin castig:=castig+a[i,1]; dg:=dg-a[i,2]; a[i,4]:=1; end else begin castig:=castig+dg*a[i,3]; a[i,4]:=dg/a[i,2];dg:=0; end; writeln (a[i,1]:6:2,a[i,2]:8:2,a[i,3]:12:2,a[i,4]:10:2); i:=i+1; end; writeln ('greutatea rucsacului este ',g-dg:0:2); writeln ('costul este ',castig:0:2); end.

Pagina 4 din 4