Sunteți pe pagina 1din 22

TEHNICI DE

PROGRAMARE

Nume:Lungu Andreea
Clasa:a XI-a B
Prof:Vlad Catalina
EXEMPLE:

• Backtracking

• Divide et impera

• Greedy

• Programare dinamica
BACKTRACKING

Backtracking este numele unui algoritm general de descoperire a


tuturor soluțiilor unei probleme de calcul, algoritm ce se bazează pe
construirea incrementală de soluții-candidat, abandonând fiecare
candidat parțial imediat ce devine clar că acesta nu are șanse să devină o
soluție validă.
IMPLEMENTARE-BACKTRACKING

• Functia Init: • Functia Succesor:

void Init (int k) { int Succesor (int k) {

v[k]=0;} if(v[k]<n) {

v[k]++;

return 1; }

else return 0; }
• Functia Valid:

int Valid (int k) {


for ( int i=1; i<k; i++)
• Functia Tipar:
if(v[i]==v[k])
void tipar()
return 0;
{for (int i=1; i<=n; i++)
return 1;}
cout<< v[i]<<“ “;
• Functia Solutie:
cout <<endl; }
{return k==n;}
1.Să se genereze toate şirurile de numere de cout << ‘\n’;}
lungime N formate doar din elemente 0 şi 1. void bt()
#include <iostream> { k = 1;
using namespace std; init();
typedef int stiva[100]; while(k > 0)
int n, k, as, ev; { as = 1;ev = 0;
stiva st; while(as && !ev)
void init() as = succesor();
{ st[k] = -1; } if(as)
int succesor() ev = valid(); }
{ if(st[k] < 1) { if(as)
st[k] = st[k] + 1; if(solutie())
return 1; } tipar();
else return 0; } else{k++; init();}
int valid() else k--; } }
{ return 1; } int main()
int solutie() { cin>>n;
{ return k == n; } bt();
void tipar() return 0;}
{ for(int i = 1;i <= k; i++)
cout << st[i] << " ";
2.Se citesc de la tastatură două numere naturale N şi P. max=a[1][1];
(0<N<P<12). Să se afişeze toate şirurile de P litere
distincte, litere alese dintre primele N litere mari ale if (a[k][j]>max)
alfabetului englez. De exemplu pentru N=4 şi P=2: AB, max=a[k][j];
AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC. for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
nr=0;
#include <iostream> if(a[i][j]>0)
nr=nr*10+a[i][j]%10;
using namespace std; a[i][j]=a[i][j]/10;
k=0;
int main() if(a[i][j]==nr)
{ k++;
int a[30][30],m,n,i,j,s,k,nr,max; cout<<k<<" "<<max<<" "<<s;
cin>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>a[i][j]; return 0;
}

{for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
s=0;
if(a[i][j]%2==0 && i%2==1 && j
%2==1)
s+=a[i][j];}
3.Să se afişeze toate anagramele unui cuvânt citit de la {for(int i=1;i<=n;i++)
tastatura. {
cout<<"("<<i<<","<<st[i]<<") ";
#include <iostream> }
using namespace std; cout<<endl;
typedef int stiva[100]; }
int n,k,as,ev; void bt()
int v[100]; {
stiva st; k=1;
void (init()) init ();
{ while (k>0)
st[k]=0; {
} as=1; ev=0;
int succesor() while(as&&!ev)
{ {
if(st[k]<n) as=succesor();
{ if (as)
st[k]+=1; ev=valid();
return 1;} }
else return 0; if(as)
} if(solutie())
int valid() tipar ();
{ else{k++;
for(int i=1;i<k;i++) init();}
if(st[k]==st[i]) else k--;
return 0; }
return 1; }
} int main()
int solutie() {cin>>n;
{ bt();}
return k==n;
}
void tipar ()
4.Să se genereze toate funcţiile bijective f:A➛B,unde {for(int i=1;i<=n;i++)
card(A)=card(B)=n. {
cout<<"("<<i<<","<<st[i]<<") ";
#include <iostream> }
using namespace std; cout<<endl;
typedef int stiva[100]; }
int n,k,as,ev; void bt()
int v[100]; {
stiva st; k=1;
void (init()) init ();
{ while (k>0)
st[k]=0; {
} as=1; ev=0;
int succesor() while(as&&!ev)
{ {
if(st[k]<n) as=succesor();
{ if (as)
st[k]+=1; ev=valid();
return 1;} }
else return 0; if(as)
} if(solutie())
int valid() tipar ();
{ else{k++;
for(int i=1;i<k;i++) init();}
if(st[k]==st[i]) else k--;
return 0; }
return 1; }
} int main()
int solutie() {cin>>n;
{ bt();}
return k==n;
}
void tipar ()
5.Să se genereze toate posibilităţile de a aranjare pe o casetă a N cout << '\n';
melodii, astfel încât melodia x să se cânte după melodia y. }
#include <iostream> void bt()
using namespace std; {
typedef int stiva[100]; k = 1;
int n, k, as, ev, x, y; init();
stiva st; while(k > 0)
void init() { {as = 1;ev = 0;
st[k] = 0; } while(as && !ev)
int succesor() { {
if(st[k] < n) { as = succesor();
st[k] = st[k] + 1; if(as)
return 1; } ev = valid();
else return 0;} }
int valid() { if(as)
for(int i = 1;i < k; ++i) if(solutie())
if(st[k] == st[i]) return 0; tipar();
if(st[k] == x && st[k - 1] != y) return 0; else{k++; init();}
return 1;} else k— ; }}
int solutie() int main()
{ { cin >> n >> x >> y;
return k == n; bt();
} return 0;

}
void tipar()
DIVIDE ET IMPERA

Divide et impera este o tehnică specială prin care se pot rezolva anumite
probleme. Tehnica Divide et Impera constă în două mari etape:
 Divide. Problema dată este împărţită în două sau mai multe
subprobleme de acelaşi tip, dar de dimensiuni mai mici. Subproblemele
se rezolvă direct, dacă dimensiunea lor permite aceasta (cazuri
elementare), sau, fiind de acelaşi tip, se rezolvă în mod recursiv, prin
acelaşi procedeu.

 Impera. Se combină soluţiile subproblemelor pentru a obţine soluţia


problemei iniţiale.
Problema 1

Calculaţi suma numerelor de la 1 la n, cu


metoda DEI.
s1=suma(li,m);
#include <iostream> s2=suma(m+1,ls);
using namespace std; s=s1+s2;
int suma(int li, int ls) }
{ return s;
int s1, s2, s, m; }
if(li==ls) int main()
s=li; {
else int n;
{ cin>>n;
m=(li+ls)/2; cout<<suma(1,n);
}
Problema 2 {
m=(li+ls)/2;
Calculaţi suma numerelor pare de la 1 la t1=op(li,m);
n, cu metoda DEI. t2=op(m+1,ls);
f=t1+t2;
#include <iostream> }
using namespace std; return f;
int op(int li, int ls) }
{ int main()
int t1, t2, f, m; {
if(li==ls) int n;
if(li%2==0) cin>>n;
f=li; cout<<op(1,n);}
else f=0;
else
Problema 3 t1=op(li,m);
t2=op(m+1,ls);
Determinaţi minimul dintre elementele if(t1<t2)
pare din vector, cu metoda DEI. f=t1;
else f=t2;
#include <iostream> }
using namespace std; return f;
int v[50]; }
int op(int li, int ls) int main()
{ {
int t1, t2, f, m; int n;
if(li==ls) cin>>n;
if(v[li]%2==0) for(int i=1;i<=n;i++)
f=v[li]; cin>>v[i];
else f=1000; cout<<op(1, n);
else }
{
m=(li+ls)/2;
METODA GREEDY

Metoda de programare Greedy se aplică problemelor de optimizare.


Aceasta metoda constă în faptul că se construieşte solutia optimă pas cu
pas, la fiecare pas fiind selectat în solutie elementul care pare „cel mai
bun/cel mai optim” la momentul respectiv, în speranta că această
alegere locală va conduce la optimul global.
• Algoritmii Greedy sunt foarte eficienti, dar nu conduc în
mod necesar la o solutie optimă. Şi nici nu este posibilă
formularea unui criteriu general conform căruia să
putem stabili exact dacă metoda Greedy rezolvă sau nu
o anumită problemă de optimizare. Din acest motiv,
orice algoritm Greedy trebuie însotit de o demonstratie
a corectitudinii sale . Demonstratia faptului că o anumită
problemă are proprietatea alegerii Greedy se face de
obicei prin inductie matematică.
• Metoda Greedy se aplică problemelor pentru care se dă o
mulţime A cu n elemente şi pentru care trebuie
determinată o submulţime a sa, S cu m elemente, care
îndeplinesc anumite condiţii, numite si conditii de optim.
Algoritmul in limbaj natural al metodei de programare
Greedy are urmatoarea structura:
Algoritm Greedy:
• se dă o mulţime A
• se cere o submulţime S din multimea A care sa:
➝ să îndeplinească anumite condiţii interne (să fie acceptabilă)
➝ să fie optimală (să realizeze un maxim sau un minim).
Principiul metodei Greedy:
• se iniţializează mulţimea soluţiilor S cu mulţimea vidă, S=Ø
• la fiecare pas se alege un anumit element x∈A (cel mai promiţător element la
momentul
respectiv) care poate conduce la o soluţie optimă
• se verifică dacă elementul ales poate fi adăugat la mulţimea soluţiilor:

• dacă da 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
• altfel
➝ el nu se mai testează ulterior
➝ procedeul continuă, până când au fost determinate toate elementele din
mulţimea soluţiilor
Problema 1 int alege(int k)
Colorarea hartii folosind metoda Greedy. { for(int i=1;i<=4;i++)
Fiind data o harta cu n tari, se cere o solutie de {
colorare a hartii, utilizand cel mult patru culori, X[k]=i;
astfel incat doua tari ce au frontiera comuna sa fie if(valid(k)) return i;
colorate diferit. Este demonstrat faptul ca sunt }
suficiente numai patru culori pentru ca orice harta sa return 0;}
poata fi colorata.
void colorare()
#include <fstream> { for(int i=1;i<=n;i++)
using namespace std; X[i]=alege(i);}
ifstream fin("colorare.in");
ofstream fout("colorare.out"); int main()
{
int A[101][101];// A[i][j]==1 pt tari vecine, 0 altfel int t1,t2;
int X[101],n;//X[i]=indicele culorii tarii i fin>>n;
char C[5][21];//culorile for(int i=1;i<=4;i++)
fin>>C[i];
void afisare() while(fin>>t1>>t2)
{ {A[t1][t2]=1;
for(int i=1;i<=n;i++) A[t2][t1]=1; }
fout<<i<<" “<<C[X[i]]<<"\n"; colorare();
fout<<endl; } afisare();
return 0;}
int valid(int k)
{ for(int i=1;i<k;i++)
if(A[i][k]==1 && X[i]==X[k]) return 0;
return 1;
}
Problema 2 }
Intr-o sala de spectacol trebuie planificate n spectacole
intr-o zi. Pentru fiecare spectacol se cunosc ora de { void afisare(int n, spectacol a[])
inceput si ora de terminare (numere intregi). for(int i=1;i<=n;i++)
Sa se planifice un numar maxim de spectacole astfel inct fout<<a[i].s<<","<<a[i].d<<" ";
sa nu fie doua spectacole care sa se suprapuna. }

#include<fstream> void greedy(int n, spectacol a[])


using namespace std; { spectacol s[100];
ifstream fin("date.in"); int i,k;
ofstream fout("date.out"); k=1;
s[1]=a[1];
struct spectacol for(i=2;i<=n;i++)
{ int s,d; if(s[k].d<a[i].s) s[++k]=a[i];
}; afisare(k,s);
}
void citire(int &n, spectacol a[])
{ fin>>n; int main()
for(int i=1;i<=n;i++) { int n;
fin>>a[i].s>>a[i].d; spectacol a[100];
} citire(n,a);
ordonare(n,a);
void ordonare(int n, spectacol a[]) greedy(n,a);
{int i,j; fin.close();
spectacol aux; fout.close();
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;
}
PROGRAMARE DINAMICA
•                 Programarea dinamică rezolvă problemele prin descompunerea
lor în subprobleme şi prin combinarea rezolvărilor acestora (termenul
„programare" se referă aici la o metodă tabulară). Spre deosebire de divide
et impera, care considera că subproblemele sunt independente,
programarea dinamică se aplică atunci când subproblemele nu sunt
independente. Într-un astfel de caz, divide et impera ar efectua calcule
redundante, rezolvând fiecare subproblemă ca şi când nu ar mai fi întâlnit-
o. Programarea dinamică, însă, salvează rezultatul fiecărei subprobleme
într-o tabelă, evitând astfel rezolvarea redundantă a aceleiaşi probleme.
•                Programarea dinamică se aplică în general problemelor de
optimizare, atunci când dorim să determinăm rapid soluţia optimă pentru o
problemă. De fapt, aplicând această tehnică determinăm una din soluţiile
optime, problema putând avea mai multe soluţii optime.
Problema 1 { fin>>A[i];
Din fisierul nrsubsircresc.in se citeste un C[i]=1;
numar natural n(n<=300) si apoi un sir cu n }
elemente numere naturale cu cel mult 9 for(int i=2;i<=n;i++)
cifre fiecare. {
Calculati si afisati in fisierul unsigned long long s=0;
nrsubsircresc.out numarul de subsiruri strict for(int j=1;j<i;j++)
crescatoare care se pot forma in sirul citit.
if(A[i]>A[j]) s=s+C[j];
C[i]=C[i]+s;
#include <fstream>
}
using namespace std;
for(int i=1;i<=n;i++)
ifstream fin("nrsubsircresc.in");
S=S+C[i];
ofstream fout("nrsubsircresc.out");
fout<<S;
int n, A[301];
return 0;
unsigned long long C[301],S;
}
int main()
{
fin>>n;
for(int i=1;i<=n;i++)
Problema 2 int main()
Se citeste un numar n si apoi un sir de n numere {
intregi. Gasiti cel mai lung subsir al sirului citit int i,j,maxx;
care are proprietatea ca elementele sunt in ordine fin>>n;
crescatoare. for(i=1;i<=n;i++) fin>>A[i];
Daca exista mai multe subsiruri de lungime L[1]=1;
maxima se va afisa unul dintre ele. for(i=2;i<=n;i++)
{
#include <fstream> maxx=0;
using namespace std; for(j=1;j<i;j++)
ifstream fin("date.in"); if(A[j]<=A[i] && L[j]>maxx)
ofstream fout("date.out"); maxx=L[j];
int n, A[10000], L[10000], maxt, pm; L[i]=maxx+1;
if(L[i]>maxt)
void afis(int k, int m) {
{ maxt=L[i];
if(m>0) pm=i;
{ }
int i=k-1; }
while(L[i]!=m-1) i--; afis(pm,maxt);
afis(i,m-1); return 0;
fout<<A[k]<<" "; }
}
}

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