Sunteți pe pagina 1din 26

Metoda greedy

 Metoda Greedy este una din cele mai directe tehnici de proiectare a
algoritmilor care se aplica la o varietate larga de probleme.In general,aceasta
metoda se aplica problemelor de optimizare.Specificul acestei metode consta
in faptul ca se construieste solutia optima pas cu pas,la fiecare pas fiind
selectat(sau „inghitit”) in solutie elementul care pare „cel mai bun”la
momentul respectiv,in speranta ca va duce la solutie optima globala.
 In metoda Greedy soluţia problemei se caută prin testarea consecutivă a
elementelor din mulţimea A şi prin includerea unora din ele în submulţimea
B.
 ***Într-un limbaj plastic, submulţimea B încearcă să „înghită” elementele
„gustoase” din mulţimea A, de unde provine şi denumirea metodei .
 !!!(greedy  lacom, hrăpăreţ).
 *Tehnica Greedy este una de optimizare, ruland mai rapid decat un
Backtraking.
 *Complexitatea unui algoritm greedy este polinomiala.
 Dezavantaje:
 *Cand nu aveti o idee mai buna legata de o problema, in timpul unui concurs,
o implementare Greedy ar putea aduce doar in jur de 30% din punctaj.
 *Exista situatii in care algoritmii clacheaza, cum ar fi problema comisului
voiajor.
 * Cu regret, metoda Greedy poate fi aplicată numai atunci cînd din enunţul
problemei poate fi dedusă regula care asigură selecţia directă a elementelor
necesare din mulţimea A.
 *Funcţia ExistaElemente returnează valoarea true dacă în mulţimea A există
elemente care satisfac criteriul (regula) de selecţie.
 *Procedura AlegeUnElement extrage din mulţimea A un astfel de element x,
iar procedura IncludeElementul înscrie elementul selectat în submulţimea B.
 !!! Iniţial B este o mulţime vidă.
 În programul ce urmează mulţimile A şi B sînt reprezentate prin vectorii
(tablourile unidimensionale) A şi B, iar numărul de elemente ale fi ecărei
mulţimi  prin variabilele întregi, respectiv n şi m. Iniţial B este o mulţime
vidă, respectiv m=0.
while ExistaElemente do
begin
AlegeUnElement(x);
IncludeElementul(x);
end
 Structura:
 Această metodă presupune că problemele pe care trebuie să le rezolvăm au
următoarea structură: 
 -se dă o mulţime A={a1, a2, ..., an} formată din n elemente; 
 - se cere să determinăm o submulţime B, care îndeplineşte anumite condiţii
pentru a fi acceptată ca soluţie.
Descriere
 Metoda greedy se folosește pentru problemele în care, dându-se o mulțime
finită A, trebuie determinată o mulțime S⊂A care să îndeplinească anumite
condiții.
 Metoda furnizează o singură soluție reprezentată prin elementele mulțimii S.
ca și în cazul metodei backtracking soluția problemei este dată de un vector
S = {x 1, x 2 ...xn} ale cărui elemente aparțin însă unei singure mulțimi A.
 Spre deosebire de metoda backtracking metoda greedy nu găsește decât o
singură soluție și în general această soluție este soluția optima.
 Ex.1. Spectacole
https://www.youtube.com/watch?v=U-h-mzr6_AU
 Să se repartizeze optim o resursă (de ex. sala de spectacole, conferințe, sport
etc.) mai multor activități care concurează pentru resursa respectivă.
 Mulțimea A este formată din cele n activități. Fiecare activitate i cu
(1≤ i≤ n) n are un timp de începere ti și un timp de terminare tf unde ti<fi și
ocupă resursa în intervalul de timp [ti, fi]. Două activități i și j sunt compatibile
dacă intervalele lor de ocupare [ti fi] și [tj fj] sunt disnjuncte, Adică dacă fi ≤ tj
sau dacă e fj ≤ ti. Cerința problemei este de a selecta o mulțime maximală de
activități compatibile. In acest caz mulțimea S este formată din activitățile care
vor folosi resursa, iar condiția pe care trebuie să o îndeplinească elementele
mulțimii s este ca ele să fie activități compatibile. In plus pentru ca repartizarea
resursei să fie optimă trebuie ca mulțimea S să conțină maximul de elemente
care îndeplinesc această condiție.
 Ex.2 Să se ocupe optim un mijloc de transport(de ex. un rucsac, un camion,
etc.) care are o capacitate maximă de ocupare(poate transporta o greutate
maximă G) cu n obiecte, fiecare obiect având greutatea gi și un profit obținut
în urma transportului ci, iar din fiecare obiect putând să se ia o fracțiune xi
[0,1]
 Mulțimea A este formată din cele n obiecte. Fiecare obiect i (1 ≤i≤n)are
eficiență a transportului ei care reprezintă profitul pentru o unitate de
greutate. Cerința problemei este de a selecta o mulțime de obiecte astfel
încât eficiență a transportului să fie maximă. Mulțimea S este formată din
obiectele care vor ocupa mijlocul de transport iar condiția pe care trebuie să
o îndeplinească elementele mulțimii S este ca prin contribuția adusă de
fiecare obiect la eficiența transportului să se obțină o eficiență maximă iar
greutatea obiectelor selectate să fie egală cu greutatea maximă a
transportului
 Ex.3 Pentru două mulțimi de numere întregi nenule C cu n elemente
C={c1,c2,…cn}și A cu m elemente A={a1,a2,…am} și n ≤m, Să se selecteze o
submulțime de n elemente din mulțimea A astfel încât expresia
E=c1*x1+c2*x2+…..+cn*xn
în care xi ∈ A să aibă valoarea maximă.

Criteriul de alegere ale elementelor xi este următorul Dacă in mulțimea A mai


există elemente care au același semn cu coeficientul ci se va alege elementul aj
pentru care termenul ci * xj are valoarea maximă, iar dacă în mulțimea A nu mai
există elemente care au același semn cu coeficientul ci se va alege elementul aj
pentru care termenul ci*xj are valoarea minima.
 Metoda greedy construiește soluția prin selectarea dintre o mulțime de
elemente a elementelor care îndeplinesc o anumită condiție. Pentru că
elementele care se selectează să aparțină soluției optime la pasul casei alege
candidatul optim pentru elementul xk al soluției.
 Pașii algoritmului greedy sunt
 pasul 1 Se initializeaza mulțimea S cu mulțimea vidă
 pasul 2 cât timp nu este o soluție a problemei și A diferit de mulțimea vidă
execută
 pasul 3 se alege din mulțimea A elementul a care este candidatul optim al soluției
pasul 4 se elimină elementul a din mulțimea A mare
 pasul 5 dacă el poate fi element al soluției atunci elementul a se adaugă la
mulțimea S Se revine la pasul 2
 pasul 6 Dacă mulțimea S este soluția problemei atunci se afișează soluția
Altfel se afișează mesajul nu s-a găsit soluție.
 pentru că algoritmul greedy să conducă la obținerea soluției optime trebuie
să fie îndeplinite două condiții
 1. alegerea optimului local pentru fiecare element al soluției duce la alegerea
soluției optime globale
 2.soluția optimă a problemei conține soluțiile optime ale subproblemelor
 Aceasta înseamnă că pentru a fi sigur că algoritmul greedy construiește
soluția optimă a problemei trebuie să se demonstreze că sunt îndeplinite cele
două condiții
Problema spectacolelor

Managerul artistic al unui festival trebuie sa selecteze o multime cat mai ampla
de spectacole ce pot fi jucate in singura sala pe care o are la dispozitie.Stiind ca i
s-au propus n spectacole si pentru fiecare spectacol i-a fost anuntat intervalul in
care se poate desfasura [Si, Fi] (Si reprezinta ora si minutul de inceput, iar Fi ora
si minutul de final al spectacolului i), scrieti un program care sa permita
spectatorilor vizionarea unui numar cat mai mare de spectacole.
 Date de intrare
Pe prima linie a fisierului de intrare spectacole.in se afla numarul n, numarul de
spectacole propus. Pe urmatoarele n linii se vor afla 4 valori, primele doua
reprezentand ora si minutul inceperii spectacolului curent, iar ultimele doua
reprezentand ora si minutul terminarii spectacolului.
 Date de iesire
Fisierul de iesire spectacole.out contine o singura linie, pe aceasta vor fi scrise
numerele de ordine ale spectacolelor care indeplinesc solutia problemei, printr-un
spatiu.
 Restrictii n <= 100
spectacole.in spectacole.out

Descrierea solutiei
Vom sorta crescator spectacolele dupa ora
de final. Vom selecta initial primul spectacol
5  (cel care se termina cel mai devreme). In
12 30 16 30  continuare vom selecta, la fiecare pasa,
15 0 18 0  primul spectacol neselectat, care nu se
524 suprapune peste cele deja selectate.
10 0 18 30
18 0 20 45
O implementare intuitiva a acestui algoritm
12 15 13 0
va fi prezentata in continuare. Pentru sortat
vom folosi metoda BubbleSort, care este
indeajuns de buna pentru limitele impuse de
problema.
void sorteaza()
#include <iostream>
#include <fstream> {
using namespace std; int aux,schimb,i;
do
ifstream f("spectacole.in"); {
ofstream g("spectacole.out"); schimb=0;
int n,inceput[100],sfarsit[100],nr[100]; for (i=0;i<n-1;++i)
if
void citeste() (sfarsit[nr[i]]>sfarsit[nr[i+1]])
{
{
int ora,min,i;
f>>n; aux=nr[i];
for (i=0;i<n;++i) nr[i]=nr[i+1];
{ nr[i+1]=aux;
nr[i]=i+1; schimb=1;
f>>ora>>min; }
inceput[i]=ora*60+min; }
f>>ora>>min; while (schimb);
sfarsit[i]=ora*60+min; }
}
f.close();
}
void rezolva()
{
int ultim,i;
for (ultim=0,i=1;i<n;++i)
if (inceput[nr[i]]>=sfarsit[nr[ultim]])
{
g<<nr[i]+1<<" ";
ultim=i;
}
g<<endl;
}

int main()
{
citeste();
sorteaza();
rezolva();
return 0;
}
Problema fractionara a rucsacului

 Se considera ca dispunem de un rucsac cu capacitatea M si de N obiecte,


definite fiecare prin greutate si valoare, ce trebuie introduce in rucsac. Se
cere o modalitate de a umple rucsacul cu obiecte , astfel incat valoarea
totala sa fie maxima. Este posibil ca oricate obiecte si bucati din obiecte sa
fie introduse.
 Date de intrare
Pe prima linie a fisierului de intrare rucsac.in se gasesc doua numere, primul
fiind N, iar al doilea M (cu specificatiile din enunt). Pe urmatoarele N linii se
gasesc, despartite printr-un spatiu valoarea obiectului curent si greutatea
acestuia.
 Date de iesire
In fisierul de iesire rucsac.out vor fi specificate numarul de ordine al obiectului,
precum si procentul in care acesta poate fi introdus in rucsac.
rucsac.in rucsac.out Descrierea solutiei
Vom reprezenta solutia problemei ca pe
un vector x. Vom ordona obiectele
5 100 descrescator tinand cont de
1000 120 valoarea/greutate. Atata timp cat
2 100 obiectele incap in rucsac, le vom adauga
500 20
4 79 in intregime.
400 200
5 100
1000 100
Completam rucsacul cu un fragment din
25 1 urmatorul obiect ce nu a fost deja
selectat.
#include <iostream> void sort()
#include <fstream> {
using namespace std; int i,aux,schimb;
do
ifstream f("rucsac.in"); {
ofstream g("rucsac.out"); schimb=0;
for (i=0;i<N-1;++i)
int o[100],N,M;
if
float val[100],greu[100],x[100],Gr; (val[o[i]]/greu[o[i]]<val[o[i+1]]/greu[o[i+1]]
)
void citeste() {
{ aux=o[i];
int i; o[i]=o[i+1];
f>>N>>M; o[i+1]=aux;
for (i=0;i<N;++i) schimb=1;
{ }
}
o[i]=i;
while (schimb);
f>>val[i]>>greu[i]; }
}
f.close();
}
void rezolva()
{ int main()
{
int i;
citeste();
for (i=0,Gr=M;i<N && sort();
Gr>greu[o[i]];++i) rezolva();
{ afisare();
x[o[i]]=1; return 0;
Gr-=greu[o[i]]; }
}
}

void afisare()
{
int i; https://www.youtube.com/watch?v=xLsuudvmrtg
for (i=0;i<N;++i)
if (x[i]) g<<i+1<<" problema #1340 Rucsac - pbinfo.ro
"<<x[i]*100<<endl;
g.close();
}
Colorarea hartii folosind metoda Greedy.

Fiind data o harta cu n tari, se cere o solutie de colorare a hartii, utilizand cel mult patru culori,
astfel incat doua tari ce au frontiera comuna sa fie colorate diferit. Este demonstrat faptul ca
sunt suficiente numai patru culori pentru ca orice harta sa poata fi colorata.
colorare.in colorare.out
6 1 alb
alb verde galben rosu 2 verde
12 3 galben
13 4 verde
14 5 rosu
15 6 galben
16
23
25
26
34
35
45
56
#include <fstream>
using namespace std;
ifstream fin("colorare.in");
ofstream fout("colorare.out");
 
int A[101][101];// A[i][j]==1 pt tari vecine, 0 altfel
int X[101],n;//X[i]=indicele culorii tarii i
char C[5][21];//culorile
 
void afisare()
{
for(int i=1;i<=n;i++)
fout<<i<<" "<<C[X[i]]<<"\n";//afisez tara si culoarea
fout<<endl;
}
 
int valid(int k)
{//1 daca tara k poate fi colorata cu X[k], 0 altfel
for(int i=1;i<k;i++)//pt tarile colorate deja
if(A[i][k]==1 && X[i]==X[k]) return 0;//exita tara invecinata care are aceeasi culoare=>0
return 1;
}

int alege(int k)
{//alege culoarea minima valida
for(int i=1;i<=4;i++)//am 4 culori
{
X[k]=i;//plasez culoarea
if(valid(k)) return i;//daca e buna o returnez
}
return 0;//daca nu putem colora
}
void colorare()
{//plaseaza in X[i] culoarea tarii i
for(int i=1;i<=n;i++)
X[i]=alege(i);//culoarea minima
}
 
int main()
{
int t1,t2;
fin>>n;//citesc nr de tari
for(int i=1;i<=4;i++)
fin>>C[i];//citesc culorile
while(fin>>t1>>t2)//pereche de tari vecine
{
A[t1][t2]=1;//pun 1 in matrice
A[t2][t1]=1;
}
colorare();
afisare();
return 0;
}
Plata unei sume de bani cu bancnote date
Se citesc 3 numere naturale S, n si e cu urmatoarele semnificatii: S este o suma de
bani care trebuie platita folosind bancnote care au valori puterile lui e de la 1 la e la
n. Se se afiseze modalitatea de plata folosind un numar minim de bancnote de tipurile
precizate. Sa se afiseze la final numarul de bancnote folosite. Datele se vor citi din
fisierul eur.in, iar rezultatele se vor afisa in fisierul eur.out.

eur.in eur.out

444 5 2 13 bancnote de valoarea 32


1 bancnote de valoarea 16
1 bancnote de valoarea 8
1 bancnote de valoarea 4
16

Explicatie: n=5, e=2 rezulta ca bancotele au valorile 1, 2, 4, 8, 16 si 32.


#include <fstream> while(S>0)
using namespace std; {
ifstream fin("eur.in"); if(S>=p) fout<<S/p<<" bancnote de
ofstream fout("eur.out"); valoarea "<<p<<endl; //bancnotele de
  valoare p
int main() t=t+S/p;//numar bancnotele folosite
S=S%p;//cat mai ramane de platit
{
p=p/e;//bancnota urmatoare ca
int S,n,e,t=0;
valoare (mai mica)
fin>>S>>n>>e; }
int p=1,k=0; fout<<t;
while(p*e<=S && k<n )//calculez bancota fin.close();
maxima (<=S avand cel mult valoarea e la n) fout.close();
{ return 0;
p=p*e; }
k++;
}
Problema comis voiajorului
Un comis-voiajor pleaca dintr-un oras, trebuie sa viziteze un numar de orase si
sa nu se intoarca in orasul de unde a plecat cu efort minim. Orice oras i este
legat printr-o sosea de orice alt oras j printr-un drum de A[i,j] kilometri.Se cere
traseul pe care trebuie sa-l urmeze comis-voiajorul, astfel incat sa parcurga un
numar minim de kilometri.

#include <iostream>
using namespace std;
int s[10],a[10][10],n,i,j,v,p,vs,vs1,mint,cost;
int main()
{
cout<<"Numar noduri=";cin>>n;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
cout<<"A["<<i<<"]["<<j<<"]=",cin>>a[i][j],a[j][i]=a[i][j];
cout<<"Nod de pornire:";cin>>v; s[v]=1;
vs1=v;
cout<<"Drumul trece prin:"<<v<<' ';
p=v;
for(i=1;i<n;i++)
{
mint=3000;
for(j=1;j<=n;j++)
if(a[v][j]!=0&&s[j]==0&&mint>a[v][j])
{
mint=a[v][j];
vs=j;
}
cost+=a[v][vs];
cout<<vs<<' ';
s[vs]=1;
v=vs;
}
cout<<p;
cost+=a[vs1][v];
cout<<endl<<"Cost="<<cost;
}

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