Sunteți pe pagina 1din 8

Algoritmi de optim local ('Greedy')

Prezentarea metodei Greedy


Algoritmii de tip greedy, backtracking si de programare dinamic se aplic unor
probleme a cror solutie poate fi exprimat sub forma unui vector de numere ntregi
(cu valori ntre 1 si n).
Intr-o problem de optimizare trebuie gsit solutia optim dintre toate solutiile
posibile. Alte clase de probleme cu solutie vectorial sunt probleme de enumerare a
tuturor solutiilor posibile si probleme de decizie, la care trebuie spus dac exist sau
nu cel putin o solutie.
Metoda Greedy se poate aplica unor probleme de optimizare cu solutie vectorial,
ca alternativ mai eficient la o cutare exhaustiv (de tip 'backtracking').
Complexitatea unui algoritm greedy este polinomial. Un algoritm Greedy este un
algoritm iterativ (nerecursiv) care determin n fiecare pas k o component x[k] a
vectorului solutie si nu 14514w221o mai revine ulterior la aceast alegere.
Numele metodei ('Greedy'= lcomie) sugereaz modul de lucru: la stabilirea valorii
lui x[k] se alege dintre candidatii posibili pe acela care este optim n pasul k, deci un
optim local.
In general, aceast alegere precipitat, grbit si care nu tine seama de valorile ce
vor fi stabilite n pasii urmtori pentru x[k+1],..x[n] nu poate garanta solutia optim a
problemei.
In functie de specificul problemei, un algoritm greedy poate conduce la solutia
optim sau la o solutie destul de bun, desi suboptimal. Rezultatul unui algoritm
greedy pentru o problem dat depinde si de datele concrete ale problemei, sau chiar
de ordinea introducerii lor.
De exemplu, n problema exprimrii unei sume de bani printr-un numr minim de
monede de valori date rezultatul (optim sau suboptim) depinde de valorile monedelor
si de valoarea sumei. Algoritmul greedy foloseste monedele n ordinea descresctoare
a valorilor lor, deci se repede la monedele de valoare maxim, care vor fi n numr
mai mic pentru aceeasi sum.
Fie monede de valori 11,5 si 1. Pentru suma 12 rezultatul algoritmului greedy va fi
optim (dou monede de valori 11 si 1), dar pentru suma 15 rezultatul algoritmului
greedy nu va fi optim (5 monede de valori 11,1,1,1,1 n loc de 3 monede de valori
5,5,5).
Dac exist mai multe solutii optime egale ca valoare, algoritmul greedy produce
numai una din aceste solutii. De exemplu, n cazul drumului de cost minim dintre dou
noduri dintr-un graf algoritmul greedy atribuit lui Dijkstra produce o singur solutie;
toate drumurile de cost minim pot fi gsite numai printr-un algoritm Backtracking.
Simplificnd putem spune c metoda greedy conduce la solutia optim pentru
problemele care au proprietatea de optim local, adic solutia optim pentru problema
de dimensiune n contine n ea solutiile optime pentru probleme de acelasi tip dar de

dimensiune mai mic. Metoda greedy se aplic si pentru probleme care nu satisfac
aceast conditie, pentru c ea produce o solutie bun, destul de apropiat de solutia
optim ntr-un timp mult mai scurt dect o metod backtracking.
In aceste cazuri metoda greedy este considerat ca o metod euristic, care
ghiceste solutia bun fr s fac o analiz exhaustiv a tuturor solutiilor posibile. O
solutie 'bun' este o solutie al crui cost este cel putin jumtate din costul solutiei
optime.
Schema general a unui algoritm Greedy
Incercarea de a folosi o schem general de algoritm greedy, care apoi s fie
adaptat fiecrei probleme specifice, are avantajul c pune n evident strategia
comun tuturor programelor bazate pe algoritmi greedy, dar si dezavantajul unor
programe neoptimizate. De aceea, n literatur programele de tip greedy apar n
forme foarte diferite si exploateaz particularittile problemei rezolvate pentru a
realiza un cod surs minim si un timp minim de executie.
O procedur greedy general contine un ciclu principal n care, la fiecare pas, se
alege o valoare pentru o component a solutiei x[k]. Alegerea se face dintr-o list de
candidati, list care poate fi unic pentru toti pasii, sau se modific (se genereaz din
nou) la fiecare pas. Vom considera o functie genCand care genereaz aceast list
de candidati si care este apelat la fiecare pas, desi uneori poate fi scoas n afara
ciclului (lista se genereaz o singur dat). Functia optim va selecta candidatul
optim din lista de candidati cand.
Lista de candidati este, ca tip abstract de date, o coad cu prioritti, pentru a
permite extragerea rapid a candidatului optim (maxim sau minim) dintr-o colectie
dinamic, la care se pot aduaga noi candidati. Teoretic, cea mai bun implementare
a unei cozi cu prioritti este un vector heap, dar din motive de simplitate se
foloseste deseori un vector.
Un vector ordonat de candidati este suficient atunci cnd lista initial de candidati
nu se mai modific prin adugarea altor candidati. O alternativ la ordonare o
reprezint selectarea si eliminarea valorii maxime (sau mimine) din vector, la fiecare
pas din ciclul principal greedy.
Selectarea unui candidat ca valoare pentru x[k] antreneaz dup sine si alte
operatii, specifice problemei, care vor fi reunite n functia include. Functia posibil
verific anumite conditii specifice problemei n functie de care candidatul optim este
sau acceptat n solutie.
Functia general greedy presupune c elementele vectorului solutie se
determin n ordinea x[1],x[2],..x[n], desi exist cazuri n care ordinea determinrii
acestor componente este alta.
// variabile globale
int n;
int x[NX];

// lungime vector solutie


// vector solutie

// algoritm greedy general

void greedy()
}
Aceast functie poate fi folosit ca atare si completat cu subprogramele
dependente de aplicatie : genCand, init, posibil, include, optim, solutie. Eventual, mai
intervine o secvent care determin valoarea lui x[k] n functie de candidatul optim
selectat.
De observat c determinarea componentelor vectorului solutie nu se face neaprat
n ordinea x[1], x[2], x[3],...x[n]. Un exemplu n acest sens l constituie algoritmul
greedy pntru colorarea nodurilor unui graf cu numr minim de culori.
O alt posibilitate este de a scrie fiecare program bazat pe un algoritm greedy fr
a defini aceste functii si exploatnd la maxim particularittile problemei date, dar
avnd ca model strategia greedy general descris anterior.
Algoritm Greedy pentru problema restului

Problema restului cere exprimarea unei sume de bani (un rest de plat) printr-un
numr minim de monede cu valori date.
Fie n tipuri de monede cu valori c[1],c[2],..c[n] si o sum R. O solutie este un
vector x[1], x[2], ..x[n] , unde x[k] este numrul de monede de valoare c[k] necesar
pentru achitarea sumei R. deci, R= x[1]*c[1] + x[2]*c[2] + ... + x[n]*c[n]. O parte din
valorile x[k] pot fi zero, dac nu se folosesc monedele corespunztoare.
Vectorul solutie, n aceast problem, poate fi considerat ca un vector de lungime
fix (egal cu numrul de monede distincte) sau ca un vector de lungime variabil, cu
x[k] egal cu numrul de monede stabilit n pasul k si considerat complet la exprimarea
ntregii sume de plat.
Algoritmul greedy ncearc s foloseasc monedele n ordinea descresctoare a
valorii lor, deci ncepe cu moneda de valoare maxim si determin numrul maxim de
monede de acest tip pentru suma de plata, apoi ncearc cu moneda imediat
inferioar s.a.m.d.
Lista de candidati este lista monedelor disponibile, ordonat descresctor; la
fiecare pas se extrage primul element din list. Pentru anumite valori ale monedelor,
acest algoritm conduce la solutia optim pentru orice sum R. Complexitatea este
O(n).
Vom exemplifica cu o instant a a problemei pentru care solutia greedy nu este si
solutia optim. Lista ordonat de monede: c[1]=11, c[2]=5, c[3]=1. Suma de
plat R= 15.
Solutia greedy : x[1]= 1, x[2]=0, x[3]= 4 (5 monede)
Solutia optim : x[1]= 0, x[2]=3, x[3]= 0 (3 monede)
// alg. greedy ptr. determinare numar minim de monede

#define M 20

// nr. maxim de monede diferite

int c[M], x[M] ;

// c = valori monede, x= numr monede

int n,rest ;

// rest = suma de plata

int greedy_rest ()
else

// putea lipsi instr. if...else

x[k]=0;
}
return (rest==0 ? 1 : -1); // -1 daca rest > 0
}
void main ()
}
Lista valorilor monedelor se introduce n ordine descresctoare sau se ordoneaz n
programul principal, nainte de apelarea functiei greedy_rest. Evolutia programului
pentru exemplul anterior este urmtoarea:
k

c[k]

x[k] R

initial

nm

15

11

Algoritm Greedy pentru problema rucsacului


Problema rucsacului, sau problema selectiei optime, se poate enunta astfel:
Fiind date n obiecte, fiecare cu greutatea g[i] si valoarea v[i] si un rucsac cu
capacitatea total Gt, s se determine ce obiecte trebuie selectate pentru a fi luate n
rucsac astfel nct greutatea lor total s nu depseasc Gt si valoarea lor s fie
maxim.
Problema poate avea dou variante :
- varianta fractionar, dac se pot lua prti din fiecare obiect;
- varianta 0/1, dac nu se pot lua dect obiecte ntregi.
In varianta 0/1 vectorul solutie are n componente si fiecare x[k] poate fi 1 sau 0
dup cum obiectul k a fost sau nu selectat.

Un algoritm greedy ordoneaz obiectele dup valoarea lor unitar (dup raportul
v[i]/g[i]) si verific fiecare obiect din aceast list de candidati dac mai are loc sau n
rucsac. Pentru problema fractionar metoda greedy conduce sigur la solutia optim,
dar pentru varianta 0/1 nu este garantat solutia optim.
Lista candidatilor este lista obiectelor, ordonat dup valoarea lor specific.
Exemplu numeric: n=3, Gt=15

g[i]

10

v[i]

20

10

12

v[i]/g[i]

2.0 1.66

1.5

Solutia greedy spune c trebuie selectat obiectul 1, valoarea selectiei fiind 20 .


Vectorul solutie:
x[1]=1, x[2]=0, x[3]=0
Solutia optim este cea care ia obiectele 2 si 3, cu valoarea total 22 si greutatea
total 14 :
x[1]=0, x[2]=1, x[3]=1
// Algoritm greedy ptr problema rucsacului
typedef struct Obiect;
// var globale
int x[M] ;
Obiect a[M];

// obiecte selectate (0 / 1)
// greutati obiecte

int n; float gt,gp,vp ;


// daca obiectul k acceptabil
int posibil(int k)
// ciclul greedy
void greedy ()
}
// compara obiecte (ptr qsort)
int Obcomp (const void * p, const void * r)
void main ()

printf (" Greutatea admis: "); scanf ("%f", &gt);


qsort (a,n,sizeof(Obiect), Obcomp);
gp=0; vp=0; // greutate si valoare partial selectie
greedy ();
printf (" Solutia optim are valoarea: %f \n",vp);
for ( i=0; i<n;i++)
if (x[i])
printf ( "%d %f %f \n", a[i].k, a[i].g, a[i].v);
}
Algoritm Greedy pentru colorarea nodurilor unui graf
Problema colorrii nodurilor unui graf cu numr minim de culori const n atribuirea
unei culori (unui numr) pentru fiecare vrf, astfel nct s nu existe dou vrfuri
adiacente care s aib aceeasi culoare. Dou noduri sunt adiacente dac sunt legate
printr-o muchie.
Algoritmul greedy de colorare ncearc s coloreze ct mai multe noduri din graf cu
o aceeasi culoare c. In acest scop se caut, la fiecare pas, acele noduri nc
necolorate care nu sunt vecine cu nodurile ce au primit deja culoarea c. Procedura
de colorare este aplicat succesiv pentru fiecare culoare posibil pn cnd se
coloreaz toate nodurile grafului.
Vectorul solutie contine culoarea fiecrui vrf si are attea componente cte vrfuri
exist n graf. Componentele vectorului solutie se obtin ntr-o ordine dependent de
datele problemei.
De exemplu, graful cu 5 vrfuri si muchiile
1-2, 2-3, 2-4, 3-5, 4-5
va fi colorat de algoritmul greedy astfel :
vrfurile 1,3,4 primesc culoarea 1 (pasul 1)
vrfurile 2,5 primesc culoarea 2 (pasul 2)
Vectorul solutie va fi:
x[1]=1, x[2]=2, x[3]=1, x[4]=1, x[5]=2
Lista de candidati este lista vrfurilor care nu au primit nc o culoare si ea se
modific la fiecare pas (prin eliminarea unor vrfuri).
Conditia de acceptare a unui vrf candidat pentru a fi colorat este ca s nu existe
muchii ntre el si alte vrfuri de aceeasi culoare.

De observat c n graful cu 5 vrfuri, dac se numeroteaz altfel vrfurile (se


inverseaz 2 cu 5), atunci metoda greedy nu mai conduce la solutia optim ( cu numai
2 culori). In acest caz, graba de a colora ct mai multe vrfuri cu o aceeasi culoare, n
ordinea numerotrii lor, nu este o bun idee.
Pentru graful cu muchiile
1-5, 5-3, 5-4, 3-2, 4-3
solutia greedy foloseste 3 culori si este
x[1]=1, x[2]=1, x[3]=2, x[4]=2, x[5]=3
# define M 30

// nr. maxim noduri graf

// variabile globale
int n,nc ;

// n=nr de noduri, nc= nr noduri colorate

int m ;

// nr de culori

int a[M][M];
int x[M];

// matrice de adiacente graf


// culori noduri

// algoritmul greedy de colorare


void colorare (int c)
}
}
// repeta ptr fiecare culoare
void main ()
Algoritm Greedy pentru acoperire cu multimi
Problema acoperirii cu multimi este o problem de optimizare clasic n selectia
unor resurse si se formuleaz astfel: Se d o multime scop S si o familie de n multimi
candidat C astfel c orice element din S apartine cel putin unei multimi din C; se cere
s se determine numrul minim de multimi din C care acoper complet pe S
(reuniunea acestor multimi include multimea S).
Exemplu de date si rezultate :
S = , n=4
C[1]= , C[2] =, C[3] = , C[4] =
Solutia optim este :
sau, mai exact

x[1]=2, x[2]=4 .

Colectia de multimi C poate fi un vector de multimi, iar solutia va fi un vector de


indici n C.
Algoritmul "greedy" selecteaz, la fiecare pas, acea multime C[k] care acoper cele
mai multe elemente neacoperite nc din S (intersectia lui C[k] cu S contine numrul
maxim de elemente). Dup alegerea unei multimi C[k] se modific multimea scop S,
eliminnd din S elementele acoperite de multimea C[k]. Ciclul "greedy" se opreste
atunci cnd multimea S devine vid.
Lista candidatilor este lista multimilor C, ordonat dup cardinalul intersectiei
dintre C[k] si S.
Exemplu de date pentru care algoritmul greedy nu determin solutia optim :
S = , n=4;
C[1]= , C[2]= , C[3] = , C[4] =
Solutia greedy este , dar solutia optim este
Urmeaz cteva secvente importante din programul care rezolv aceast
problem.

#define M 20

// nr. maxim de multimi candidat

Set cand[M], scop, aux;


int n ;

// n= nr. de multimi candidat

void greedy ()
}
printS (cand[imax]);
removeAll (scop,cand[imax]);

// elimina elemente acoperite de candidat

} while ( ! emptyS(scop));
}
Secventa anterioar nu a verificat dac problema admite solutie, dar aceast
verificare se poate face imediat dup citirea datelor: se reunesc toate multimile
candidati si se verific dac multimea scop este continut n reuniunea candidatilor.

S-ar putea să vă placă și