Sunteți pe pagina 1din 6

Lecția 3.

Aplicații Greedy
Cuprins:
Problema #1340 Rucsac.......................................................................................................................................................... 1
Problema #1373 Reactivi(OJI 2004, clasa IX-a) ....................................................................................................................... 3
Problema #950 Cerc3(Olimpiada de Informatică, etapa pe sector, Bucureşti, 2011) ............................................................ 4
Temă : ..................................................................................................................................................................................... 6

Problema #1340 Rucsac


Se consideră că dispunem de un rucsac cu capacitatea Gmax și de N obiecte, definite fiecare prin greutate și valoare,
ce trebuie introduce in rucsac. Se cere o modalitate de a umple rucsacul cu obiecte, astfel încât valoarea totală să fie
maximă. Putem lua fragmente dint-un obiect.

Exemplu: greutatea maximă a rucsacului Gmax=30

inițial
Obiect 1 2 3 4
Greutate 10 5 12 20
Valoare 60 50 60 140
Eficiență(valoare/greutate) 6 10 5 7
Se ordonează descrescător după eficiența la transport

După ordonare
Obiect 2 4 1 3
Greutate 5 20 10 12
Valoare 50 140 60 60
Eficiență(valoare/greutate) 10 7 6 5

Soluția este:

Vom reprezenta soluția problemei ca pe un vector de structuri. Vom ordona obiectele descrescător ținând cont de
raportul valoarea/greutate. Atâta timp cât obiectele încap în rucsac, le vom adaugă în întregime și putem întâlni una din
următoarele situații:
 obiectele alese au o greutate totală egală cu a rucsacului;
 mai există loc în rucsac, dar nu mai încape nici un obiect întreg, caz în care adăugăm o fracțiune de obiect.

După ordonare
Greutate rămasă rucsac 30 30-5=25 25-20=5 0
Obiect 2 4 1 3
Greutate 5 20 10 12
Valoare 50 140 60 60
Eficiență(valoare/greutate) 10 7 6 5
Fracțiune selectată 1 1 0.5 (5/10) -
(greutate rămasă/greutatea obiectului
Câștig 0+50=50 50+140=190 190+30=220
Sursa c++:

#include <iostream>
#include <fstream>
using namespace std;
ifstream f("obiecte.in");
struct obiect
{
int id;
float greutate, valoare, eficienta;
};

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


{
f>>n>>Gmax;
for(int i=1; i<=n; i++)
{
f>>a[i].greutate>>a[i].valoare;
a[i].eficienta=a[i].valoare/a[i].greutate;
a[i].id=i;
}
}
void ordonez(obiect a[1001], int n)
{
obiect aux;
for(int i=1; i<n; i++)
for(int j=i+1; j<=n; j++)
if(a[i].eficienta<a[j].eficienta)
{
aux=a[i];
a[i]=a[j];
a[j]=aux;
}
}
void greedy(obiect a[1001], int n, float Gmax)
{ int s[1001],m;
float x[1001];
ordonez(a, n);
float c=0;
m=0;
for(int i=1; i<=n && Gmax!=0; i++)
if(Gmax>a[i].greutate)
{ c=c + a[i].valoare;
s[++m]=i;
x[m]=1;
Gmax-=a[i].greutate;
}
else
{ c=c + (Gmax/a[i].greutate)*a[i].valoare;
s[++m]=i;
x[m]=Gmax/a[i].greutate;
Gmax=0;
}
/*for(int i=1; i<=m; i++)
cout<<"obiect "<<a[s[i]].id<<" de greutate "<<a[s[i]].greutate<<
" fractiune "<<x[i]<<endl;*/

cout<<c;
}

int main()
{
obiect a[1001];
int n;
float Gmax;
citire(a, n, Gmax);
greedy(a, n, Gmax);
return 0; }
Problema #1373 Reactivi(OJI 2004, clasa IX-a)
Într-un laborator de analize chimice se utilizează N reactivi. Se știe că, pentru a evita accidentele sau deprecierea
reactivilor, aceștia trebuie să fie stocați în condiții de mediu speciale. Mai exact, pentru fiecare reactiv x, se precizează
intervalul de temperatură [minx, maxx] în care trebuie să se încadreze temperatura de stocare a acestuia.
Reactivii vor fi plasați în frigidere. Orice frigider are un dispozitiv cu ajutorul căruia putem stabili temperatura (constantă)
care va fi in interiorul acelui frigider (exprimată într-un număr întreg de grade Celsius).

Scrieți un program care să determine numărul minim de frigidere necesare pentru stocarea reactivilor chimici.

Date de intrare
Fișierul de intrare reactivi.in conține:
 pe prima linie numărul natural N, care reprezintă numărul de reactivi;
 pe fiecare dintre următoarele N linii se află min max (două numere întregi separate printr-un spațiu); numerele
de pe linia x+1 reprezintă temperatura minimă, respectiv temperatura maximă de stocare a reactivului x.

Date de ieșire
Fișierul de ieșire reactivi.out va conține o singură linie pe care este scris numărul minim de frigidere necesar.

Restricții și precizări
 1 <= N <= 8000
 -100 <= minx <= maxx <= 100 (numere întregi, reprezentând grade Celsius), pentru orice x de la 1 la N un frigider
poate conține un număr nelimitat de reactivi
Exemplu:
reactivi.in reactivi.out
5 2
-10 10
10 12
-20 10
7 10
7 8

Rezolvare:

inițial
Reactiv 1 2 3 4 5
Temperatura minimă -10 10 -20 7 7
Temperatura maximă 10 12 10 10 8

Ordonăm crescător după temperatura maximă:

inițial
Reactiv 1 2 3 4 5
Temperatura minimă 7 -10 -20 7 10
Temperatura maximă 8 10 10 10 12
Ptmax 1 1 1 1 5
Nr 1 1 1 1 2

Memorăm în PTmax indicele primului reactiv(ea este cea mai mare temperatură) și inițializăm numărul de frigidere
necesare cu 1. Parcurgem restul reactivilor și dacă temperatura minimă a reactivului curent este mai mare decât
temperatura maximă păstrată, atunci vom avea nevoie de un alt frigider:

v[PTmax].y < v[i].x, oricare ar fi 𝑖 = ̅̅̅̅̅


2, 𝑛
Soluție C++:

#include <bits/stdc++.h>
using namespace std;

ifstream fin("reactivi.in");
ofstream fout("reactivi.out");

struct react {
int x,y;
}v[8005];

void citeste(react v[], int &n)


{ fin >> n;
for (int i = 1;i <=n; i++)
fin >> v[i].x >> v[i].y;
}

bool cmp(react a, react b)


{
return a.y < b.y;
}

void greedy(react v[], int n)


{ sort(v+1, v + n+1, cmp);
int nr = 1,PTmax = 1; ///pozitia frigiderului cu temperatura maximă
for (int i = 2;i<=n; i++) {
if (v[PTmax].y < v[i].x)
{
nr++;
PTmax = i;
}
}
fout << nr;

}
int main()
{
int n;
citeste(v,n);
greedy(v,n);
return 0;
}

Problema #950 Cerc3(Olimpiada de Informatică, etapa pe sector, Bucureşti, 2011)


Se consideră pe axa Ox din plan n puncte distincte reprezentând centrele a n cercuri numerotate cu numerele distincte de
la 1 la n. Pentru fiecare cerc k se cunosc abscisa xk a centrului său şi raza sa rk. Să se scrie un program care să determine
numărul y maxim de cercuri exterioare două câte două dintre cele n.

Date de intrare
Fișierul de intrare cerc3.in conține pe prima linie pe prima linie, o valoare naturală n, reprezentând numărul de cercuri, iar
pe următoarele n linii câte două numere naturale, separate printr-un spaţiu, care reprezintă abscisa x1 a centrului primului
cerc şi raza sa r1,…, abscisa xn a centrului celui de-al n-lea cerc şi raza sa rn.

Date de ieșire
Fișierul de ieșire cerc3.out va conține o linie pe care va fi scris numărul natural y reprezentând numărul maxim de cercuri
exterioare ale căror centre sunt situate pe axa Ox.
Exemplu:
cerc3.in cerc3.out
8 4
3 1
1 4
8 1
11 2
15 2
16 6
21 2
21 1

Explicații și indicații de rezolvare:

Numărul maxim de cercuri exterioare două câte două este y=4. De exemplu, pot fi alese cele 4 cercuri colorate din imaginea
de mai jos:

Fiecărui cerc cu centrul în xk şi raza rk îi corespunde intervalul [xk - rk , xk + rk ]. Problema constă acum în a
determina un număr maxim de intervale disjuncte, adică problema spectacolelor.
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
ifstream f("cerc3.in");
ofstream g("cerc3.out");

struct cerc{ int a;


int b;
}c[301];
int n;
void citire(cerc c[], int &n)
{ int x, r;
f>>n;
for(int i=1;i<=n; i++)
{f>>x>>r;
c[i].a=x-r;
c[i].b=x +r;
}
}
bool compara(cerc c1, cerc c2)
{ return (c1.b < c2.b);
}
void greedy(cerc c[], int &n)
{
sort(c+1,c+n+1,compara);
for(int i=1;i<=n; i++)
cout<<c[i].a<<' '<<c[i].b<<endl;
int nr=1;
int sf=c[1].b;
for(int i=2;i<=n; i++)
if( c[i].a>sf)
{
nr++;
sf=c[i].b;
}
g<<nr;
}
int main()
{
citire(c, n);
greedy(c, n);
return 0;
}

Temă :
 #2684, #400, #403(daca stiti siruri de caractere) #556, #1207, #2044
 https://practice.geeksforgeeks.org/problems/shop-in-candy-store/0#ExpectOP
 https://practice.geeksforgeeks.org/problems/smallest-number/0

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