Documente Academic
Documente Profesional
Documente Cultură
Consideraii teoretice
Explicarea numelui
n limba englez cuvntul greedy nseamn lacom. Algoritmii de tip greedy sunt algoritmi lacomi.
Ei vor s construiasc ntr-un mod ct mai rapid soluia problemei, fr a sta mult pe gnduri.
Algoritmii de tip greedy se caracterizeaz prin luarea unor decizii rapide care duc la gsirea
unei soluii a problemei. Nu ntotdeauna asemenea decizii rapide duc la o soluie optim, dar vom
vedea c exist anumite tipuri de probleme unde se pot obine soluii optime sau foarte apropiate de
optim.
Algoritmii de tip Greedy se aplic la acele probleme unde datele de intrare sunt organizate sub
forma unei mulimi A i se cere gsirea unei submulimi BA care s ndeplineasc anumite condiii
astfel nct s fie acceptat ca soluie posibil.
n general pot s existe mai multe submulimi BA care s reprezinte soluii posibile ale
problemei. Dintre toate aceste submulimi B se pot selecta, conform unui anumit criteriu, anumite
submulimi B* care reprezint soluii optime ale problemei. Scopul este de a gsi, dac este posibil,
una din mulimile B*. Dac acest lucru nu este posibil, atunci scopul este gsirea unei mulimi B
care s fie ct mai aproape de mulimile B*, conform criteriului de optimalitate impus.
Implementare
Ca i schem general de lucru, exist dou variante de implementare a algoritmilor de tip Greedy.
Prima variant folosete dou funcii caracteristice: alege i posibil. alege este o funcie care
are rolul de a selecta urmtorul element din mulimea A care s fie prelucrat. Funcia posibil verific
dac un element poate fi adugat soluiei intermediare Bi astfel nct noua soluie Bi+1 care s-ar
obine s fie o soluie valid. Prezentm n continuare pseudocodul pentru aceast prim variant
greedy. Se consider c numrul de elemente al mulimii A este n.
B = multimea vida
for (i=0; i<n; i++)
{
x = alege(A)
if (posibil(B,x))
* adauga elementul x la multimea B
}
Dificultatea la aceast prim variant const n scrierea funciei alege. Dac funcia alege este bine
conceput, atunci putem fi siguri c soluia B gsit este o soluie optim. Dac funcia alege nu este
foarte bine conceput, atunci soluia B gsit va fi doar o soluie posibil i nu va fi optim. Ea se
poate apropia ns mai mult sau mai puin de soluia optim B*, n funcie de criteriul de selecie
implementat.
A doua variant de implementare difer de prima prin faptul c face o etap iniial de
prelucrare a mulimii A. Practic se face o sortare a elementelor mulimii A, conform unui anumit
criteriu. Dup sortare, elementele vor fi prelucrate direct n ordirea rezultat. Prezentm n
continuare pseudocodul pentru aceast a doua variant greedy.
B = multimea vida
prelucreaza(A)
for (i=0; i<n; i++)
{
x = A[i]
if (posibil(B,x))
* adauga elementul x la multimea B
}
La a doua variant, dificultatea funciei alege nu a disprut, ci s-a transferat funciei prelucreaza.
Dac prelucrarea mulimii A este bine fcut, atunci se va ajunge n mod sigur la o soluie optim.
Altfel se va obine doar o soluie posibil, mai mult sau mai puin apropiat de optim.
Exemple
Problema comis-voiajorului
Enun Se condider n orae. Se cunosc distanele dintre oricare dou orae. Un comis-voiajor
trebuie s treac prin toate cele n orae. Se cere s se determine un drum care pornete dintr-un ora,
trece exact o dat prin fiecare din celelalte orae i apoi revine la primul ora, astfel nct lungimea
drumului s fie minim.
Rezolvare Pentru gsirea unei soluii optime la aceast problem este nevoie de algoritmi cu timp
de rulare foarte mare (de ordin exponenial O(2n)). n situaiile practice asemenea algoritmi cu timp
foarte mare de rulare nu sunt acceptabili. Ca urmare se face un compromis i se accept algoritmi
care nu gsesc soluia optim ci doar o soluie aproape de optim, dar au n schimb un timp de rulare
mic. Propunem n continuare o soluie greedy la aceast problem. Ideea este urmtoarea. Se
pornete dintr-un ora oarecare. Se caut drumul cel mai scurt care pleac din oraul respectiv ctre
orae nevizitate nc. Se parcurge acel drum i se ajunge ntr-un alt ora. Aici din nou se caut cel
mai scurt drum ctre oraele nevizitate nc. Se parcurge i acest drum, ajungndu-se ntr-un nou
ora. Repetnd aceti pai se parcurg toate oraele. La final se parcurge drumul care duce napoi
spre primul ora.
S considerm exemplul din figura 1. Avem 4 orae cu distanele reprezentate n figur.
Pornim vizitarea oraelor din oraul 0. De aici alegem drumul cel mai scurt ctre oraele nevizitate,
i anume (0,2) de lungime 2. Ajuni n oraul 2, alegem din nou drumul cel mai scurt spre oraele
nevizitate, i anume (2,3) de lungime 1. Din oraul 3 mai avem doar un singur ora nevizitat, 1, aa
c alegem drumul spre el (3,1) de lungime 1. n acest moment am parcurs toate oraele i ne
rentoarcem n oraul 0 pe drumul (1,0) de lungime 4. Drumul rezultat este 0, 2, 3, 1, 0, iar distana
total de parcurs este 2 + 1 + 1 + 4 = 8.
Implementare Distanele ntre orae le memorm ntr-un tablou bidimensional D. Distana ntre
oraele (i,j) va fi memorat n elementul di,j al matricii. n termeni Greedy, mulimea iniial A este
mulimea tuturor perechilor de orae. Pentru reeaua de orae din figura 2 mulimea A conine
elementele {(0,1), (0,2), (0,3), (1,2), (1,3), (2,3)}. Mulimea B care trebuie gsit va conine o parte
din aceste perechi de orae, i anume acele perechi care nlnuite s formeze un drum ce trece prin
toate oraele. Dac avem un numr de n orae, atunci mulimea B va conine n perechi de orae.
n implementare nu vom lucra cu mulimea A sub aceast form explicit de perechi de
orae, ci vom folosi matricea distanelor D. De asemenea drumul comis-voiajorului nu l vom pstra
sub form de perechi de orae, ci sub forma unui sir al oraelor.
Pentru a memora drumul parcurs de comis-voiajor, folosim un tablou unidimensional drum.
n acest tablou vom memora indicii oraelor parcuse, n ordinea parcurgerii.
Pentru a ti care orae au fost parcurse, facem o marcare logic a oraelor folosind un tablou
unidimensional vizitat. Elementele din acest tablou care au valoarea 1 reprezint orae vizitate.
Cod surs n continuare este prezentat codul surs n limbajul C care implementeaz algoritmul
descris mai sus.
#include <stdio.h>
int main(void)
{
FILE *fin;
int i, j;
int count, cost, min, j_min;
Fiierul cu date de intrare pentru reeaua de orae din figura 2 este urmtorul:
4
0 4 2 7
4 0 2 1
2 2 0 1
7 1 1 0
mbuntiri Algoritmul greedy prezentat se poate mbunti pentru a furniza soluii mai aproape
de soluia optim. O variant de mbuntire este s nu se porneasc doar din primul ora la
parcurgerea drumului. Se poate relua calculul avnd ca punct de pornire fiecare ora pe rnd i se
poate memora minimul global astfel obinut.
Probleme propuse
Enun Se consider n orae. Pentru diferite perechi de orae (i, j), 0<i<n, 0<j<n se cunoate costul
conectrii lor directe ci,j. Nu toate perechile de orae pot fi conectate; pentru perechile care nu pot fi
conectate nu se precizeaz costul. Se cere s se construiasc o reea prin care oricare dou orae s
fie conectate ntre ele direct sau indirect i costul total al conectrii s fie minim.
Rezolvare Se poate arta c reeaua de conectare cerut este un arbore. Problema mai este
cunoscut i ca problema determinrii arborelui parial de cost minim ntr-un graf. Pentru aceast
problem exist un algoritm greedy de rezolvare numit algoritmul lui Prim. n literatura de
specialitate exist argumentarea matematic a faptului c acest algoritm gsete ntotdeauna soluia
optim de conectare a oraelor.
Se construiete arborele parial minim n manier greedy, adugnd cte un nod la fiecare
pas. La nceput de tot arborele parial este vid, nu conine nici un nod. Primul pas const n
adugarea unui nod arbitrar n arbore. Pe urm, la fiecare pas se caut muchia de cost minim care
pornete dintr-un nod deja adugat la arbore i ajunge ntr-un nod care nu este n arbore. Se adaug
n arbore nodul n care sfrete muchia gsit.
S considerm spre exemplu o reea de 7 orae numerotate de la 0 la 6. Costurile de
conectare a oraelor sunt redate n figura 2.
Arborele minim este redat cu linii ngroate. El a fost construit pas cu pas, conform procedeului
descris mai sus. Iniial arborele a fost vid. La primul pas s-a adugat un nod arbitrar, i anume nodul
0.
Pe urm s-a ales muchia de cost minim care pleac din nodul 0 ctre celelalte noduri.
Muchia de cost minim a fost (0,2) de cost 10. Nodul 2 a fost adugat n arbore.
La urmtorul pas s-a ales muchia de cost minim care pleac din nodurile 0 sau 2 ctre
celelalte noduri. Muchia aleas a fost (2,1) de cost 9. Nodul 1 a fost adugat n arbore.
La urmtorul pas s-a ales muchia de cost minim care pleac din nodurile 0, 2 sau 1 ctre
nodurile nc neintroduse n arbore. Muchia aleas a fost (1,5) de cost 3. Nodul 5 a fost adugat n
arbore.
Urmtoarea muchie aleas a fost (5,4) de cost 2. Nodul 4 a fost adugat n arbore. Apoi a
fost aleas muchia (4,6) de cost 2 i nodul 6 a fost adugat i el n arbore.
Pe urm a fost aleas muchia (1,3) de cost 4 i nodul 3 a fost introdus n arbore. n acest
moment algoritmul s-a ncheiat deoarece toate oraele au fost conectate la reea. Costul total al
conectrii a fost 10 + 9 + 3 + 2 + 2 + 4 = 30.
...
/* Numarul de orase. */
int n;
int main(void)
{
...
...
...
...
...
}
return 0;
}