Sunteți pe pagina 1din 12

2.

5 METODA GREEDY

Metoda Greedy (greedy = lacom), denumită și metoda optimului local, reprezintă o


metodă de programare utilizată în probleme de optimizare şi care furnizează o singură soluţie
(optimul global) care este obţinută prin alegeri succesive ale optimului local.
Algoritmii de tip greedy, asemenea algoritmilor backtracking și de programare dinamică
se utilizează pentru rezolvarea unor probleme a căror soluție se poate exprima sub forma unui
vector de numere întregi. În comparație cu metoda backtracking, metoda Greedy nu va determina
toate soluțiile problemei. Metoda va găsi doar o singură soluție și, în general soluția găsită este
soluția optimă.
Metoda se aplică problemelor în care se dă o mulţime A cu n elemente şi trebuie
determinată o submulţime a sa, S cu m elemente, care îndeplinesc anumite condiţii. Algoritmul
va determina la fiecare pas k o componentă x[k] a vectorului soluție și spre deosebire de
algoritmul backtracking, nu mai revine ulterior la această alegere. Pentru ca elementele care se
selectează să aparțină soluției optime, la pasul k se va alege candidatul care este optim pentru
elementul x[k] al soluției deci un optim local.
Pașii metodei greedy sunt:
1.se iniţializează mulţimea soluţiilor S cu mulţimea vidă, S=Ø;
2.la fiecare pas se alege un anumit element x∈A, candidatul optim la momentul
respectiv, care poate conduce la o soluţie optimă;
3.se verifică dacă elementul ales poate fi adăugat la mulţimea soluţiilor:
- dacă se poate adăuga, atunci va fi adăugat şi mulţimea soluţiilor devine S=S ∪ {x} - un
element introdus în mulţimea S nu va mai putea fi eliminat;
- dacă nu se poate adăuga, el nu se mai testează ulterior.
4.procedeul continuă, până când au fost determinate toate elementele din mulţimea
soluţiilor.Structura generală a unei aplicații greedy: (Sorin, 2006, p. 129)
Sol = Ø;
Repetă
Alege x ϵ A;
Dacă este posibil atunci Sol  Sol + x;
Până când am obținut soluția
Afișează Sol;
- De regulă metoda greedy are o complexitate de O (n k).
- Există destul de puține probleme pentru care se poate aplica această metodă.
- Metoda greedy se aplică atunci când știm că se ajunge la soluția dorită.
1.SUMĂ MAXIMĂ

Se dă o mulţime A={a1, a2, . . ., an} cu elemente reale. Să se determine o submulţime a


lui S astfel încât suma elementelor submulţimii să fie maximă.
Rezolvare: Se vor căuta între elementele vectorului A doar elementele mai mari sau
egale cu 0. Se va utiliza un subprogram greedy ( ) pentru implementarea algoritmului.
#include <iostream>
using namespace std;
int n,i,m;
float A[100], S[100];
void greedy ( )
{ for(i = 1; i <= n; i ++ )
if ( A[ i ] >= 0 )
{ m ++ ;
S[ m ] = A[ i ]; } }
int main()
{ cout << " Numarul de elemente n = " ; cin >> n ;
cout << endl <<" Elementele vectorului " << endl ;
for ( i = 1 ; i <= n ; i++ )
{ cout <<"A[" <<i<<"] = "; cin >> A[ i ] ;}
greedy();
cout << " Submultimea este formata din: " ;
for ( i= 1; i <= m ;i ++ ) cout << S [ i ] <<' ';
return 0; }

2.Se dă o mulţime A={a1, a2, . . ., an} cu elemente întregi. Să se determine cele mai
mari două elemente ale mulţimii.

#include <iostream>
#include<fstream>
using namespace std;
ifstream f("date.in");
int n,i,a,maxi1,maxi2,aux;
int main()
{
f>>n;
for(i=1;i<=n;i++)
{
f>>a;
if(a>maxi1)maxi1=a;
if(maxi2<maxi1){aux=maxi1; maxi1=maxi2; maxi2=aux;}
}
cout<<maxi1<<" "<<maxi2;
}

3.PROBLEMA PLANIFICĂRII SPECTACOLELOR

Într-o sală de spectacol trebuie planificate n spectacole într-o zi. Pentru fiecare spectacol
se cunosc ora de început și ora de terminare (numere întregi). Să se planifice un număr maxim
de spectacole astfel încât să nu fie doua spectacole care să se suprapună.
Rezolvare:
Soluția problemei se va construi după următorul algoritm:
Pas 1 Se sortează spectacolele după ora terminării lor;
Pas 2 Primul spectacol ales este cel care se termină cel mai devreme;
Pas 3 Se alege primul spectacol care îndeplinește condiția că începe după ce s-a terminat
ultimul spectacol programat;
Pas 4 Dacă nu s-a găsit un asemenea spectacol atunci algoritmul se termină altfel se
programează spectacolul găsit și se reia pasul 3.
Exemplu fișierul date.in conține pe prima linie numărul de spectacole și apoi ora de
începere și ora de terminare pentru fiecare spectacol:
8
9 11
12 13
8 10
10 12
16 18
14 16
20 22
19 21
Soluția problemei va fi:
8,10 10,12 12,13 14,16 16,18 19,21
#include<fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");
struct spectacol
{ int s,d; };
void citire(int &n, spectacol a[])
{
fin>>n;
for(int i=1;i<=n;i++)
fin>>a[i].s>>a[i].d;
}
void ordonare(int n, spectacol a[])
{
int i,j;
spectacol aux;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++)
if(a[i].d>a[j].d)
{aux=a[i]; a[i]=a[j]; a[j]=aux; }}
void afisare(int n, spectacol a[])
{
for(int i=1;i<=n;i++)
fout<<a[i].s<<","<<a[i].d<<" ";
}
void greedy(int n, spectacol a[])
{
spectacol s[100];
int i,k;
k=1;
s[1]=a[1];
for(i=2;i<=n;i++)
if(s[k].d<a[i].s) s[++k]=a[i];
afisare(k,s);
}

int main()
{
int n;
spectacol a[100];
citire(n,a);
ordonare(n,a);
greedy(n,a);
fin.close();
fout.close();
}

4.PROBLEMA RUCSACULUI (CAZUL CONTINUU)


O persoană are un rucsac cu care poate transporta o greutate maximă g. Persoana are la
dispoziție n obiecte pentru care se cunosc greutatea și câștigul obținut. Să se precizeze ce obiecte
trebuie să transporte persoana astfel încât câștigul total sa fie maxim și să nu se depășească
greutatea maximă a rucsacului.
Rezolvare:
 se determină pentru fiecare obiect eficiența de transport ( raportul dintre câștig și
greutate)
 se ordonează obiectele în ordine descrescătoare a eficienței de transport
 atât timp cât nu s-a atins greutatea maximă a rucsacului și nu au fost luate în
considerare toate obiectele, se va selecta obiectul cu eficiența de transport maximă existând două
situații: - obiectul încape în totalitate în rucsac, caz în care se va scădea din greutatea rămasă de
încărcat greutatea obiectului și se adună la câștig, câștigul obținut din transportul obiectului
adăugat;
- obiectul nu încape în totalitate în rucsac, deci se va determina partea care poate fi
transportată, se adună câștigul obținut din transportul acestei părți și se tipărește procentul care s-
a încărcat din obiect.
Exemplu:
g=3 n=3 adică greutatea ce poate fi transportată este 3 și avem la dispoziție 3 obiecte.
obiectele (greutate,câștig):
22
14
36
Soluția obținută (greutate, câștig, raport tăiere):
1,4,1
3,6,0.6667 (al doilea obiect se încarcă în raport de 2/3)
câștig maxim obținut =8

#include<fstream>
#include<iomanip>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");
struct obiect
{ float g,c,r;//greutate, castig, raportul cat se ia din obiect };

void citire(float &g, int &n, obiect a[])


{
fin>>g>>n;
for(int i=1;i<=n;i++)
{ fin>>a[i].g>>a[i].c;
a[i].r=0;//initial nu se foloseste obiectul
}}
void ordonare(int n, obiect a[])//ordonare dupa castig/greutate
{
int i,j;
obiect aux;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++)
if(a[i].c/a[i].g<a[j].c/a[j].g)
{
aux=a[i]; a[i]=a[j]; a[j]=aux;
}}
void afisare(int n, obiect a[])
{
float c=0;
for(int i=1;i<=n;i++)

{ fout<<a[i].g<<","<<a[i].c<<","<<setprecision(4)<<a[i].r<<endl;
c=c+a[i].c*a[i].r;
}
fout<<"castig maxim="<<c;
}

void greedy(float g, int n, obiect a[])


{
obiect s[100];
int i,k;
float sp=0;
k=0; i=1;
while(sp<g)
{
if(sp+a[i].g<=g)
{ sp=sp+a[i].g;
s[++k]=a[i];
s[k].r=1;//obiect intreg
}
else
{
s[++k]=a[i];
s[k].r=(g-sp)/a[i].g;//obiect fractionat
sp=g;
}
i++;
}
afisare(k,s);
}
int main()
{
int n;
obiect a[100];
float g;
citire(g,n,a);
ordonare(n,a);
greedy(g,n,a);
fin.close();
fout.close();
return 0;}

5.PROBLEMA COMIS-VOIAJORULUI

Un comis - voiajor pleacă dintr-un oraș, trebuie să viziteze un număr de orașe și să se


întoarcă în orașul inițial cu un efort minim. Orice oraș i este legat de un alt oraș j printr-un drum
de A[ i ][ j ] kilometri. Să se determine traseul pe care trebuie să-l parcurgă comis-voiajorul care
să aibă un număr minim de kilometri.
Rezolvare: Se va alege un oraș de pornire. la fiecare pas se va selecta un alt oraș din cele
neselectate până acum și aflat la distanță minimă față de orașul de pornire. Algoritmul se încheie
atunci când s-au selectat toate orașele.

#include<fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");

int s[100],viz[100],n,x;
int a[100][100];

void citire()
{
int i,j;
fin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
fin>>a[i][j];
}

void afișare()
{ for(int i=1;i<=n;i++) fout<<s[i]<< ' ';
fout<<endl<<x;
}

void voiajor(int k)
{ int min=100000,imin;
for(int i=1;i<=n;i++)
if(!viz[i] && a[s[k-1]][i]<min && i!=s[k-1])
{
min=a[s[k-1]][i];
imin=i;
}
s[k]=imin;
viz[imin]=1;
x=x+a[s[k-1]][imin];
if(k==n) afisare();
else voiajor(k+1);
}

int main()
{
citire();
s[1]=1;
viz[1]=1;
voiajor(2);
fin.close();
fout.close();
return 0;
}

În ceea ce privește complexitatea, se poate afirma că algoritmii de tip greedy sunt


eficienți, operația principală fiind cea de selecție a elementelor. Dacă este necesară o ordonare a
elementelor mulțimii A atunci această operație de sortare este cea mai costisitoare. Ordinul de
complexitate al algoritmilor de tip “greedy” poate fi O(n2) sau O(nlgn) sau O(n), în funcție de
natura elementelor din A și algoritmul de sortare folosit.

6.Fiind dată o hartă cu n țări, se cere o soluție de colorare a hărții, utilizând cel mult
patru culori, astfel încât două țări ce au frontiera comună să fie colorate diferit.

Date.in
6
alb verde galben rosu
12
13
14
15
16
23
25
26
34
35
45
56
#include <fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");

int a[101][101];
int x[101],n;
char c[5][21];

void afisare()
{
for(int i=1;i<=n;i++)
fout<<i<<" "<<c[x[i]]<<endl;
fout<<endl;
}
int valid(int k)
{ for(int i=1;i<k;i++)
if(a[i][k]==1 && x[i]==x[k]) return 0;
return 1;
}
int alege(int k)
{ for(int i=1;i<=4;i++)
{
x[k]=i;
if(valid(k)) return i;
}
return 0;
}
void colorare()
{ for(int i=1;i<=n;i++)
x[i]=alege(i);
}

int main()
{
int t1,t2;
fin>>n;
for(int i=1;i<=4;i++)
fin>>c[i];
while(fin>>t1>>t2)
{
a[t1][t2]=1;//pun 1 in matrice
a[t2][t1]=1;
}
colorare();
afisare();
fin.close();
fout.close();
return 0;
}

7.Se citesc 3 numere naturale S, n și e cu următoarele semnificații: S este o sumă de


bani care trebuie plătită folosind bancnote care au valori puterile lui e de la 1 la e la n. Să se
afișeze modalitatea de plată folosind un număr minim de bancnote de tipurile precizate. Să se
afișeze la final numărul de bancnote folosite.
#include <fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");

int main()
{
int S,n,e,t=0;
fin>>S>>n>>e;
int p=1,k=0;
while(p*e<=S && k<n
{
p=p*e;
k++;
}
while(S>0)
{
if(S>=p) fout<<S/p<<" bancnote de valoarea "<<p<<endl;
t=t+S/p;
S=S % p;
p=p/e;
}
fout<<t;
fin.close();
fout.close();
return 0;
}

8.Fiind dată o tabla de șah de dimensiunea n × n și un cal în colțul stânga sus al acesteia,
se cere să se deplaseze calul pe tablă astfel încât să treacă o singură dată prin fiecare pătrat al
tablei.
#include<fstream>
#include<iomanip>
using namespace std;
const int dx[8]={-1,1,2,2,1,-1,-2,-2};
const int dy[8]={-2,-2,-1,1,2,2,1,-1};
int a[201][201],n,ok;
ifstream fin("date.in");
ofstream fout("date.out");

void afis()
{ int i,j;
fout<<"n="<<n<<endl;
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++) fout<<setw(4)<<a[i][j]<<" ";
fout<<endl;
}
fout<<endl;
ok=1;
}

int inside(int i,int j)


{
return i>=1 && i<=n && j>=1 && j<=n;
}
int nm(int i, int j)
{
int inou,jnou,k,x=0;
for(k=0;k<8;k++)
{ inou=i+dx[k];
jnou=j+dy[k];
if(inside(inou,jnou) && a[inou][jnou]==0) x++;
}
return x;
}

void greedy(int i, int j, int pas)


{ int k,v,min=9,inou,jnou,ii,jj;
if(!ok)
{
a[i][j]=pas;
if (pas==n*n) afis();
else for(k=0;k<8;k++)
{ inou=i+dx[k];
jnou=j+dy[k];
if (inside(inou,jnou) && a[inou][jnou]==0)
{
v=nm(inou,jnou);
if(v<min) { min=v; ii=inou; jj=jnou;}
}
}
if(min!=9) greedy(ii,jj,pas+1);
a[i][j]=0;
}
}

int main()
{ fin>>n;
greedy(1,1,1);
fout.close();
return 0;
}

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