Documente Academic
Documente Profesional
Documente Cultură
Probleme rezolvate
1. Un om doreşte să urce o scară cu N trepte (1<N<100). El poate urca
una sau două trepte la un moment dat. Fiind o fire curioasă, el vrea să ştie în
câte moduri poate urca această scară. Programul va citi valoarea N de la
tastatură şi va afişa pe ecran rezultatul cerut.
Exemplu :
Date de intrare Rezultat
N=4 5 posibilităţi
void Citire()
{
ifstream fin("subsecventa.in");
fin>>N;
for(int i=1;i<=N;i++)
fin>>X[i];
}
void Rezolvare()
{
//DP[i]-Secventa de suma maxima care se termina pe pozitia i
DP[0]=0;
void Afisare()
{
//Solutia va fi maximul din sirul DP, adica secventa de suma
//maxima care se termina pe una din pozitiile sirului
SMax=-oo;
for(int i=1;i<=N;i++)
SMax=max(SMax,DP[i]);
cout<<"Subsecventa de suma maxima este: "<<SMax;
}
int main()
{
Citire();
Rezolvare();
Afisare();
return 0;
}
3. Se dă un şir S = (s1, s2, .., sN) de lungime N (1 ≤ N ≤ 1 000). Un subşir
al şirului este de forma: S' = (si1, si2, ..., siK), i1 < i2 < ... < iK . Se cere să se
determine un subşir al şirului S, care este ordonat strict crescător şi care are
lungimea maximă.
Datele de intrare se citesc din fisierul subsir.in, care conţine pe prima linie
numărul N, iar pe linia a doua N numere naturale, despărţite de un spaţiu,
reprezentând elementele şirului. Programul va afişa pe ecran un număr natural,
care reprezintă lungimea maximă a unui subşir crescator, respectiv un subşir
crescător maximal.
Exemplu:
Date de intrare Rezultat
N=5 Lungimea maximă a unui subşir este 3.
S = 24 12 15 15 19 Un subşir crescător maximal este: 12 15 19.
void Afisare()
{
int i,Max=0,PMax=0;
for(int i=1;i<=N;i++)
{
if(DP[i]>Max)
{
Max=DP[i];
PMax=i;
}
}
// Solutia va fi maximul dintre valorile sirului DP,
cout<<Max<<"\n";
int main()
{
Citire();
Rezolvare();
Afisare();
return 0;
}
4. Se dau două şiruri: A = (a1, a2, .., aM), cu M elemente (1 ≤ M ≤ 1 000),
respectiv B = (b1, b2, .., bN) cu N elemente (1 ≤ N ≤ 1 000). Să se găsească cel
mai lung subşir care apare atât în şirul A cât şi în şirul B.
Datele de intrare se citesc din fişierul cmlsc.in, care conţine pe prima linie
un număr N, pe linia a doua N numere, pe linia a treia numărul M, apoi pe linia
următoare M numere. Programul va afişa pe ecran un număr, reprezentând
lungimea subşirului comun maximal, respectiv un subşir comun de lungime
maximă.
Exemplu:
Date de intrare Rezultat
N=5
A=17398 Lungimea maximă a unui subşir comun este 2.
M=3 Un subşir comun maximal este: 7 8 .
B=758
int main()
{
Citire();
Rezolvare();
Afisare();
return 0;
}
void Citire()
{
ifstream fin("edit.in");
fin.getline(S1,NMax);
fin.getline(S2,NMax);
N=strlen(S1);
M=strlen(S2);
}
void Rezolvare()
{
int i,j;
//DP[i][j] - numarul minim de operatii pentru a
transforma //sirul format din primele i caractere din S1
//in sirul format din primele j caractere din S2
for(i=1;i<=N;i++)
DP[i][0]=i;
for(j=1;j<=M;j++)
DP[0][j]=j;
for(i=1;i<=N;i++)
for(j=1;j<=M;j++)
{
DP[i][j]=min(DP[i-1][j-1]+(S1[i]!=S2[j]),min(DP[i][j-
1]+1,DP[i-1][j]+1));
}
}
void Afisare()
{
//Solutia va fi DP[N][M] - numarul minim de operatii
pentru //a transforma sirul S1 in sirul S2
cout<<DP[N][M]<<'\n';
}
int main()
{
Citire();
Rezolvare();
Afisare();
return 0;
}
6. Se consideră un triunghi de numere care are pe prima linie un număr,
pe a doua linie două numere, pe a treia linie trei numere, triunghiul având în total
N linii (1 ≤ N ≤ 1000). Scrieţi un program care să calculeze cea mai mare dintre
sumele numerelor ce apar pe drumurile ce pleacă din vârf şi ajung la bază, astfel
încât în fiecare drum succesorul unui număr se află pe rândul de mai jos
dedesubt sau pe diagonală la dreapta. Datele de intrare se citesc din fişierul
triunghi.in, începând cu numărul de linii şi continuând cu triunghiul de numere.
Programul va afişa pe ecran valoarea cerută.
Exemplu:
Date de intrare Rezultat
5 Suma maximă este este 30.
7
38
810
2744
45265
void Rezolvare()
{
int i,j;
//DP[i][j] – Suma maxima a unui triunghi cu varful
// in pozitia (i,j)
for (i=1;i<=N;i++)
DP[N][i]=A[N][i];
for (i=N-1;i>=1;i--)
for (j=1;j<=i;j++)
DP[i][j]=A[i][j] + max(DP[i+1][j],DP[i+1][j+1]);
}
void Afisare()
{
//Solutia va fi DP[1][1]
//Suma maxima a triunghiului cu varful (1,1)
cout<<DP[1][1]<<"\n";
}
int main()
{
Citire();
Rezolvare();
Afisare();
return 0;
}
int main()
{
Citire();
Rezolvare();
Afisare();
return 0;
}
10. Fermierul Ion are o fermă de formă circulară, unde cresc N (2≤N≤
100000) găini. Ferma a fost împărţită în N sectoare, numerotate de la 1 la N,
astfel încât oricare două sectoare având numere consecutive sunt adiacente (se
află unul lângă altul). În plus, primul şi ultimul sector sunt adiacente. În fiecare
sector se află câte o găina, iar aceasta depune un anumit număr de ouă în
fiecare zi. După ce găinile depun ouăle, fermierul Ion doreşte să le adune, pentru
a le mânca. Deoarece fermierul este foarte lacom, de fiecare dată el alege două
sectoare adiacente din care adună ouăle simultan. Din păcate, din cauza
lăcomiei sale, găinile din sectoarele vecine cu cele două alese se sperie şi devin
violente, motiv pentru care fermierul nu mai poate aduna ouăle din aceste
sectoare. În exemplul din problemă, dacă fermierul adună simultan ouăle din
sectoarele 1 şi 2, el nu va mai putea aduna ouăle din sectoarele 3 şi 10.
Determinaţi numărul maxim de ouă pe care le poate aduna fermierul Ion, în urma
aplicării strategiei sale lacome.
Datele de intrare se citesc din fişierul oo.in care conţine pe prima linie
numărul de sectoare în care este împărţită ferma. Pe următoarea linie se află N
numere întregi din intervalul [0,100], reprezentând numărul de ouă depuse de
fiecare găina, în ordinea sectoarelor în care se află acestea.
Programul va afisşa numărul maxim de ouă pe care le poate aduna fermierul Ion.
(Osman Ay, Stelele Informaticii 2003, clasele 9-10)
Exemplu:
Date de intrare Rezultat
10
Numărul maxim de ouă este 20.
1 2 1 7 6 0 1 0 4 3
int main ()
{
Citire();
Rezolvare();
Afisare();
return 0;
}
12. O staţie de gaz are un rezervor în care poate depozita cel mult L (1 ≤
L ≤ 1 000) litri de gaz, dar se poate depozita o cantitate suplimentară de gaz într-
un rezervor închiriat de capacitate nelimitată pentru care se va plăti o taxă de C
dolari pentru fiecare litru de gaz depozitat de la o zi la alta. Staţia se
aprovizionează cu gaz cel mult o dată pe zi. Preţul unui litru de gaz este de D
dolari. Pentru fiecare aprovizionare trebuie plătită o taxă de P dolari în plus faţă
de costul gazului comandat. În aceste condiţii, comandarea unei cantităţi mari de
gaz poate creşte costul depozitării. Staţia de gaz se închide după N zile (1 ≤ N ≤
2 000 ). Aceasta livrează clienţilor săi Gi (1 ≤ Gi ≤ 1 000, i 1, n ) litri de gaz la
sfârşitul fiecărei zile i, unde i = 1, 2, ..., N. Problema constă în a alege cantităţile
de gaz ce vor fi comandate zilnic, astfel încât la sfârşitul celei de a N-a zi
întreaga cantitate de pe stoc să fie consumată şi costul total să fie minim. Se
consideră că rezervorul este iniţial gol. Scrieţi un program care determină costul
total minim pentru ca staţia să îşi servească clienţii în cele N zile şi întreaga
cantitate de gaz să fie consumată la sfârşitul celei de a N-a zi.
Datele de intrare se citesc din fişierul gaz.in care conţine pe prima linie
patru numere naturale separate prin câte un spaţiu, L P D C (1 ≤ P, D, C ≤ 5 000),
cu semnificaţia din enunţ. A doua linie conţine numerele naturale N G1 G2 ... GN,
separate prin câte un spaţiu, unde N reprezintă numărul zilelor după care staţia
va fi închisă şi Gi cantitatea de gaz necesară zilei i, i 1, n .
int main()
{
Citire ();
Rezolvare();
Afisare ();
return 0;
}
14. Gigel s-a decis să îşi cumpere un teren într-o zonă a oraşului în care
locuieşte. Oraşul este reprezentat printr-o matrice pătratică de dimensiune N (4 ≤
N ≤ 150), iar fiecare pătrat al matricii reprezintă o zonă de dimensiune unitară a
oraşului. Pentru fiecare zonă de dimensiune unitară a oraşului se cunoaşte
valoarea ei, care este un număr întreg între -150 şi 150. Gigel vrea să îşi
cumpere un teren de forma dreptunghiulară având P linii şi Q coloane, inclus
complet în oraş, care să aibă valoarea maximă posibilă. Valoarea terenului este
reprezentată de suma valorilor zonelor de dimensiune unitară pe care le include
(în număr de P*Q).
Datele de intrare se citesc din fişierul teren.in care conţine pe prima linie
numerele N, P şi Q (separate prin câte un spaţiu). Pe următoarele N linii se vor
afla câte N numere întregi (separate prin spaţii), reprezentând valorile zonelor de
dimensiune unitară care fac parte din oraş. Programul va afişa valoarea maximă
a terenului pe care vrea să îl cumpere Gigel.
Exemplu:
Date de intrare Rezultat
423
-1 -1 -1 -1
-1 1 -1 -1 Valoarea maximă a unui teren este 1.
-1 -1 -1 4
-1 -1 -1 -1
using namespace std;
#include <iostream>
#include <fstream>
#define oo 1000000000
int N, P, Q, A[155][155], S=-oo;
void Citire ()
{
ifstream fin ("teren.in");
fin >> N >> P >> Q;
for (int i=1; i<=N; ++i)
for (int j=1; j<=N; ++j)
fin >> A[i][j];
}
void Determinare_Sume_Partiale()
{
//A[i][j] – suma elementelor din submatricea cu coltul
//stanga sus (1,1) si dreapta jos (I,j)
for (int i=1; i<=N; ++i)
for (int j=1; j<=N; ++j)
A[i][j]+=(A[i-1][j]+A[i][j-1]-A[i-1][j-1]);
}
void Rezolvare()
{
Determinare_Sume_Partiale();
for (int i=P; i<=N; ++i)
for (int j=Q; j<=N; ++j)
S=max(S,A[i][j]-A[i-P][j]-A[i][j-Q]+A[i-P][j-
Q]);
}
void Afisare ()
{
cout << S << "\n";
}
int main(){
Citire ();
Rezolvare();
Afisare ();
return 0;
}
15. Se dă o tablă de şah, de dimensiune standard 8/8, pe care se află
diverse piese de şah. Un cal se află pe poziţia (i,j). Dorim să mutăm calul în
poziţia (k,l) dacă acest lucru este posibil, folosind oricare din cele 8 mutări
posibile ale calului în orice succesiune, astfel încât numărul de mutări să fie
minim.
Datele vor fi citite din fişierul cal.in, fiind date în următoarea formă:
*-**-***
**-***-*
*****-**
***-****
********
******-*
********
********
unde "*" înseamnă poziţie liberă, iar "-" poziţie ocupată.
Programul va afişa numărul minim în cazul în care calul poate ajunge la
poziţia (c,d) sau un mesaj corespunzător dacă nu poate ajunge.
using namespace std;
#include<fstream>
#include <iostream>
#define N 10
int A[N][N],X1,Y1,X2,Y2;
int L[N*N],C[N*N],K,dX[]={-2,-2,-1,-1,1,1,2,2},dY[]={-1,1,-
2,2,-2,2,-1,1};
void Citire()
{
ifstream fin("cal.in");
for(int i=1;i<=8;i++)
for(int j=1;j<=8;j++)
{
char x;
fin>>x;
if(x=='-')
A[i][j]=-1;
}
fin>>X1>>Y1>>X2>>Y2;
}
void Rezolvare()
{
A[X1][Y1]=1;
L[1]=X1;C[1]=Y1;
K=1;
for(int i=1;i<=K;i++)
{
int x,y;
x=L[i]; y=C[i];
for(int l=0;l<8;l++)
{
int xnou,ynou;
xnou=x+dX[l];
ynou=y+dY[l];
if (Valid(xnou,ynou) && A[xnou][ynou]==0)
{
A[xnou][ynou]=A[x][y]+1;
K++;
L[K]=xnou;
C[K]=ynou;
}
}
}
}
void Afisare()
{
if(A[X2][Y2])
cout<<A[X2][Y2]-1<<'\n';
else
cout<<"Imposibil";
}
int main()
{
Citire();
Rezolvare();
Afisare();
return 0;
}
16. Fie o pereche de numere de forma (a,b) asupra căreia putem face
următoarele operaţii:
(a,b) -> (a-b,b)
(a,b) -> (a+b,b)
(a,b) -> (b,a)
Dându-se valorile (a,b) de la tastatură, să se determine numărul minim de
operaţii care pot fi efectuate astfel încât să se obţină perechea (c,d). Programul
va afişa acest număr minim în cazul în care se poate obţine perechea (c,d) sau
un mesaj corespunzător dacă nu se poate obţine.
using namespace std;
#include<iostream>
#include<cstring>
#define NMax 1005
#define oo 1<<30
struct Pereche
{
int first,second;
};
int A,B,C,D,DP[NMax][NMax],K;
Pereche Coada[NMax*NMax];
void Citire()
{
cout<<"A=";cin>>A;
cout<<"B=";cin>>B;
cout<<"C=";cin>>C;
cout<<"D=";cin>>D;
}
void Rezolvare()
{
memset(DP,-1,sizeof(DP));
Coada[++K].first=A;Coada[K].second=B;
DP[A][B]=0;
for(int i=1;i<=K&&DP[C][D]==-1;i++)
{
int x,y;
x=Coada[i].first;
y=Coada[i].second;
if(Valid(x+y,y))
{
P[x+y][y]=DP[x][y]+1;
Coada[++K].first=x+y;Coada[K].second=y;
}
if(Valid(x-y,y))
{
DP[x-y][y]=DP[x][y]+1;
Coada[++K].first=x-y;Coada[K].second=y;
}
if(Valid(y,x))
{
DP[y][x]=DP[x][y]+1;
Coada[++K].first=y;Coada[K].second=x;
}
}
}
void Afisare()
{
if(DP[C][D]!=-1)
cout<<DP[C][D]<<'\n';
else
cout<<"Imposibil";
}
int main()
{
Citire();
Rezolvare();
Afisare();
return 0;
}
#include <iostream>
#include <fstream>
#include <vector>
#define NMax 100005
#define oo 1<<30
using namespace std;
ifstream fin("mvc.in");
int N,Use[NMax],C[NMax],DP[2][NMax],Sol;
vector <int> G[NMax];
void Citire()
{
fin>>N;
for(int i=1;i<=N;i++)
fin>>C[i];
for(int i=1;i<=N;i++)
{
int x,y;
fin>>x>>y;
G[x].push_back(y);
G[y].push_back(x);
}
}
void DFS(int Nod)
{
Use[Nod]=1;
DP[0][Nod]=0;
DP[1][Nod]=C[Nod];
for(unsigned int i=0;i < G[Nod].size();i++)
{
int Fiu=G[Nod][i];
if(!Use[Fiu])
{
DFS(Fiu);
DP[0][Nod]+=DP[1][Fiu];
DP[1][Nod]+=min(DP[0][Fiu],DP[1][Fiu]);
}
}
}
void Rezolvare()
{
//DP[0][Nod]–Costul minim al a unei submultimi pentru
--subarborele nodului Nod,din care nu face parte nodul Nod
//DP[1][Nod]–Costul minim al a unei submultimi pentru
--subarborele nodului Nod,din care face parte nodul Nod
DFS(1);
}
void Afisare()
{
// Solutia va fi minimul dintre DP[0][1] si DP[1][1]
// Costul minim pentru arborele cu radacina in 1
// daca se alege nodul 1 sau nu se alege nodul 1
Sol=min(DP[0][1],DP[1][1]);
cout<<Sol<<'\n';
}
int main(){
Citire();
Rezolvare();
Afisare();
return 0;
}
Probleme propuse
2. Vasele 1, 2 şi 3 au volumele A1, A2, A3. Iniţial vasul 1 este plin cu apă.
Se poate face o singură operaţie, şi anume se toarnă apa dintr-un vas până când
acesta se goleşte sau până când vasul în care se toarnă se umple. Problema
este că din număr minim de asemenea operaţii, să se ajungă la situatia ca într-
unul din vase să se afle o cantitate Q de apă.
Indicaţie: Se rezolvă prin Lee, A[i,j,k] = numărul minim de operaţii pentru
a ajunge de la situaţia iniţială la situaţia în care în primul butoi se află "i" unităţi de
apă, în al 2-lea butoi "j" unităţi de apă, iar în al 3-lea "k" unităţi de apă. Algoritmul
se încheie când A[Q,i,j] sau A[i,Q,j] sau A[i,j,Q] devine iniţializat.
7. Ilinca este o fetiţă căreia îi place foarte mult să deseneze; ea a făcut multe
desene pe care le-a numerotat de la 1 la d şi apoi le-a multiplicat (toate copiile
poartă acelaşi număr ca şi originalul după care au fost făcute). În vacanţă s-a
hotărât să-şi deschidă propria expoziţie pe gardul bunicilor care are mai multe
scânduri; pe fiecare scândură ea aşează o planşă (un desen original sau o
copie). Ilinca ţine foarte mult la desenele ei şi doreşte ca fiecare desen să apară
de cel puţin k ori (folosind originalul şi copiile acestuia). Ilinca se întreabă în câte
moduri ar putea aranja expoziţia. Două moduri de aranjare sunt considerate
distincte dacă diferă cel puţin prin numărul unei planşe (de exemplu: 2 1 3 3 este
aceeaşi expoziţie ca şi 2 3 1 3, dar este diferită de 2 1 3 1 şi de 1 3 3
1).Cunoscând n numărul de scânduri din gard, d numărul desenelor originale şi k
numărul minim de apariţii al fiecărui desen, să se determine în câte moduri poate
fi aranjată expoziţia, ştiind că Ilinca are la dispoziţie oricâte copii doreşte.
Datele de intrare se citesc din fişierul expozitie.in care conţine 3 numere: n d
k – numărul de scânduri, numărul desenelor originale, respectiv numărul minim
de apariţii. Programul va afişa numărul modurilor distincte de aranjare a
expoziţiei.
1 ≤ n ≤ 500 1 ≤ d ≤ 500 0 ≤ k ≤ n
(Carmen Popescu, OJI 2012 - clasa a 10-a)