Sunteți pe pagina 1din 51

Facultatea de Matematic i Informatic

Lecii de pregtire Admitere 2017

Rezolvarea problemelor
folosind metoda
backtracking
Slide-uri realizate de
prof. Florentin Ipate
Exemplu: ieirea din labirint

2
Exemplu: aranjarea a n regine

3
Exemplu: rezolvarea unui sudoku

4
Exemplu: rezolvarea unui sudoku

5
Agenda
 Metoda Backtracking: prezentare general
Varianta nerecursiv
Varianta recursiv
 Exemple
Generarea permutrilor, aranjamentelor, combinrilor
Problema celor n regine
Problema colorrii hrilor
iruri de paranteze ce se nchid corect
Partiiile unui numr natural
 Probleme de backtracking date la admitere

6
Metoda Backtracking
 Se folosete n cazul problemelor a cror soluie este un
vector x = (x1, x2, ..., xn) unde fiecare xi apartine unei
mulimi finite Ai, elementele mulimilor Ai aflndu-se ntr-
o relaie de ordine bine stabilit.
 ntre componentele xi ale vectorului sunt precizate anumite
relaii numite condiii interne.

 Mulimea se numete spaiul soluiilor posibile.

 Soluiile posibile care satisfac condiiile interne se numesc


soluii rezultat.
 Generarea tuturor elementelor produsului cartezian nu este
acceptabil (cutare exhaustiv ntr-un spaiu de dimensiuni
mari).
7
Metoda Backtracking
 Dimensiunea spaiului soluiilor posibile
A1 A2 ... An are |A1| |A2| ... |An| elemente
 Metoda backtracking ncearc micorarea timpului de
calcul, realiznd o cutare sistematic n spaiul
soluiilor posibile.
 Vectorul  este construit progresiv, ncepnd cu prima
component. Se avanseaz cu o valoare  dac este
xk
satisfcut condiia de continuare.
 Condiiile de continuare rezult de obicei din condiiile
interne. Ele sunt strict necesare, ideal fiind s fie i
suficiente.

8
Metoda Backtracking
 Backtracking = parcurgerea limitat (conform
condiiilor de continuare) n adncime a unui
arbore.
 Spaiul soluiilor este organizat ca un arbore
un vrf este viabil dac sunt anse s se
gseasc o soluie explornd subarborele cu
rdcina n acel vrf
sunt explorai numai subarborii cu rdcini
viabile

9
Backtracking nerecursiv
k1;
ct timp k > 0 repet
dac ( k = n+1 ) atunci {am gsit o soluie}
prelucreaz(x1,..., xn); {afieaz soluie}
kk-1; {revenire dup gsirea soluiei}
altfel
dac (   netestat) atunci
xkv; { atribuie }
dac (x1,...,xk ndeplinete cond. continuare)
atunci
kk+1; { avanseaz }
sfrit dac
altfel
kk-1; { revenire }
sfrit dac
sfrit ct timp
10
Pentru cazul particular Ai ={1, 2,,n}, i=1,...,n, algoritmul se
rescrie astfel:
xi 0, i=1,...,n
k1;
ct timp k > 0 repet
dac ( k = n+1 ) atunci {am gsit o soluie}
prelucreaz(x1,..., xn); {afieaz soluie}
kk-1; {revenire dup gsirea soluiei}
altfel
dac (xk<n) atunci
xk xk + 1; { atribuie }
dac (x1,...,xk ndeplinete cond. continuare)
atunci
kk+1; { avanseaz }
sfrit dac
altfel
xk0; kk-1; { revenire }
sfrit dac
sfrit ct timp
11
Backtracking recursiv
Descriem varianta recursiv pentru cazul particular
Ai ={1, 2,,n}, i=1,...,n. Apelul iniial este backrec(1).

procedura backrec(k)
dac (k=n+1) atunci {am gsit o soluie}
prelucreaz(x1,..., xn); {afieaz soluie}
altfel
i1;
ct timp i<=n repet {toate valorile posibile }
xki;
dac (x1,...,xk ndeplinete cond. continuare)
atunci backrec(k+1);
sfrit dac
ii+1;
sfrit ct timp
sfrit dac
sfrit procedura 12
Exemple
1. Generarea permutrilor, aranjamentelor,
combinrilor
2. Problema celor n regine
3. Colorarea hrilor
4. iruri de paranteze ce se nchid corect
5. Partiiile unui numr natural

6. Generarea unor numere cu proprieti specificate


7. Generarea produsului cartezian
8. Generarea tuturor soluiilor unei probleme, pentru a
alege dintre acestea o soluie care minimizeaz sau
maximizeaz o expresie

13
Generarea permutrilor
Se citete un numr natural n. S se genereze
toate permutrile mulimii {1, 2, , n}.

 Reprezentarea soluiei ?
 Condiii interne ?
 Condiii de continuare ?

 x = (x1, x2,, xn)


 Condiii interne: pentru orice ij, xixj
 Condiii de continuare: pentru orice i<k, xixk

14
Exemplu: n = 3
= {1,2,3} {1,2,3} {1,2,3}
x = (x1, x2, x3)

1 2 3

1 2 3 1 2 3 1 2 3
1

1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3

(1,2,3) (1,3,2) (2,1,3) (2,3,1) (3,1,2) (3,2,1)

15
1 2 3 1
1 2 2 2 2 3 3
1 1 1 1 1 1 1 1

2 3 1 2 3
3 3 1 1 1 1 2
1 1 2 2 2 2 2 2

1 2 3 1 2
3 3 3 3 1 1 1
2 2 2 2 3 3 3 3

3 1 2 3
1 2 2 2 2 3
3 3 3 3 3 3
16
type stiva = array[1..20] of int n, nrsol = 0, x[20];
integer;
var n,nrsol:integer;
procedure tipar(x:stiva); void tipar(int x[])
var i:integer; {
begin nrsol++;
nrsol := nrsol+1; printf("Solutia %d:",
write('Solutia ',nrsol,': '); nrsol);
for i:=1 to n do for(int i=0; i<n; i++)
write(x[i],' '); printf(" %d ", x[i]);
writeln; printf("\n");
end; }
function cont(x:stiva; int cont(int x[], int k)
k:integer):boolean; {
var i:integer; for(int i=0;i<k;i++)
begin if (x[i]==x[k])
cont:=true; return 0;
for i:=1 to k-1 do return 1;
if (x[i]=x[k]) then }
cont:=false;
end;

17
procedure back(); void back()
var k,i:integer; {
begin int k = 0;
for i:=1 to n do x[i]:=0; for(int i=0; i<n; i++)
k:=1; x[i]=0;
while k>0 do while(k > -1)
begin {
if k=n+1 then begin if (k==n) {
tipar(x); tipar(x);
k:=k-1; k--; }
end else
else if(x[k]<n)
if x[k]<n then {
begin x[k]++;
x[k]:=x[k]+1; if (cont(x,k))
if cont(x,k) then k++;
k:=k+1; }
end else {
else begin x[k]=0;
x[k]:=0; k--;
k:=k-1; }
end; }
end; }
end; 18
procedure backrec(k:integer); void backrec(int k)
var i:integer; {
begin if(k==n)
if k=n+1 then tipar(x);
tipar(x) else
else for(int i=1;i<=n ;i++)
for i:=1 to n do {
begin x[k]=i;
x[k]:=i; if (cont(x,k))
if cont(x,k) then backrec(k+1);
backrec(k+1); }
end }
end;
BEGIN int main()
write('Dati n: '); readln(n); {
nrsol := 0; printf("Dati n:");
back(); scanf("%d",&n);
{ sau } back();
{ backrec(1); } // sau
readkey; // backrec(0);
END. return 0;
}
19
Problema celor n regine
Fiind dat o tabl de ah de dimensiune n x n, se
cer toate soluiile de aranjare a n regine astfel
nct s nu atace (s nu se afle dou regine pe
aceeai linie, coloan sau diagonal).
1 2 3 4 1 2 3 4
1  Reprezentarea soluiei ? 1
2  Condiii interne ? 2
3  Condiii de continuare ? 3
4 4

 x = (x1, x2,, xn), xk = coloana pe care este plasat regina


de pe linia k
 Condiii interne: pentru orice ij, xixj i |xi-xj||j-i|.
 Condiii de continuare: pentru orice i<k, xixk i |xi-xk|k-i.20
Problema celor n regine
Algoritmul este acelai ca la permutri, se modific doar
condiiile de continuare

function cont(x:stiva; int cont(int x[], int k)


k:integer):boolean; {
var i:integer;
begin
cont:=true;
for i:=1 to k-1 do for(int i=0;i<k;i++)
if (x[i]=x[k]) or if ((x[i]==x[k]) ||
(abs(x[k]-x[i])=abs(k-i)) (abs(x[k]-x[i])== k-i))
then return 0;
cont:=false; return 1;
end;
}

21
Generarea aranjamentelor
Se citesc dou numere naturale n i p. S se
genereze toate submulimile mulimii {1,2, ..., n}
de p elemente. Dou mulimi cu aceleai elemente,
la care ordinea acestora difer, sunt considerate
diferite.
n=3, p=2
 Reprezentarea soluiei ? 12
 Condiii interne ? 13
 Condiii de continuare ? 21
23
31
 x = (x1, x2,, xp)
32
 Condiii interne: pentru orice ij, xixj
 Condiii de continuare: pentru orice i<k, xixk

22
Algoritmul este acelai ca la permutri, se modific doar
dimensiunea stivei

procedure tipar(x:stiva); void tipar(int x[])


var i:integer; {
begin nrsol++;
nrsol := nrsol+1; printf("Solutia %d:",
write('Solutia ',nrsol,': '); nrsol);
for i:=1 to p do for(int i=0; i<p; i++)
write(x[i],' '); printf(" %d ", x[i]);
writeln; printf("\n");
end; }

procedure back(); void back()


var k,i:integer; {
begin int k = 0;
for i:=1 to p do x[i]:=0; for(int i=0; i<p; i++)
k:=1; x[i]=0;
while k>0 do while(k > -1){
begin if (k==p) { tipar(x);
if k=p+1 then begin k--; }
else
23
Generarea combinrilor
Se citesc dou numere naturale n i p, np. S se
genereze toate submulimile mulimii {1,2, ..., n}
avnd p elemente. Dou mulimi cu aceleai
elemente, la care ordinea acestora difer, sunt
considerate egale.
n=4, p=3
 Reprezentarea soluiei ?
123
 Condiii interne ?
124
 Condiii de continuare ?
134
234
 x = (x1, x2,, xp)
 Condiii interne: pentru orice i<j, xi<xj
 Condiii de continuare: pentru orice k>1, xk-1<xk

24
Algoritmul este acelai ca la aranjamente, se modific n plus
funcia de continuare

function cont(x:stiva; int cont(int x[], int k)


k:integer):boolean; {
var i:integer;
begin if (k>0)
cont:=true; if (x[k] <= x[k-1])
if k>1 then return 0;
if x[k]<=x[k-1] then return 1;
cont:=false; }
end;

procedure back(); void back()


var k,i:integer; {
begin int k = 0;
for i:=1 to p do x[i]:=0; for(int i=0; i<p; i++)
k:=1; x[i]=0;
while k>0 do while(k > -1){
begin if (k==p) { tipar(x);
if k=p+1 then begin k--; }
else
25
ntrebare
 Este important evitarea situaiei n care se tiprete de
dou ori o mulime, din cauz c este scris n alt
ordine: {1,2,4} vs. {1,4,2}.
 Ce valori poate s ia elementul de pe nivelul k al stivei?
a) ntre 1 si n
b) ntre k si p
c) ntre k si n-p+k
d) ntre x[k-1]+1 si n-p+k

26
Colorarea hrilor
Se consider o hart. Se cere colorarea ei folosind cel
mult 4 culori, astfel nct oricare dou ri vecine s fie
colorate diferit.
 Reprezentarea soluiei ?
 Condiii interne ?
 Condiii de continuare ?

Problema matematic: orice hart poate fi


colorat utiliznd cel mult 4 culori (rezultat
demonstrat n 1976 de ctre Appel and Haken unul
dintre primele rezultate obinute folosind tehnica
demonstrrii asistate de calculator)
27
Colorarea hrilor
 Reprezentarea soluiei: x = (x1, x2,, xn), unde xk =
culoarea curent cu care este colorat ara k, xk
{1,2,3,4} (pk = 1, uk = 4).
 Condiiile interne: xi xj pentru orice dou ri vecine i
i j.
 Condiii de continuare: xi xk pentru orice ar
i{1,2,,k-1} vecin cu ara k.
 Folosim o matrice a pentru a memora relaia de
vecintate dintre ri:
1, dac i i j sunt ri vecine


0, 1, dac rile i i j sunt vecine
dac i i j nu sunt ri vecine
aij =
0, altfel
28
function cont(x:vector; int cont(int x[], int k){
k:integer):boolean;
var i:integer;
begin
cont:=true; for(int i=0;i<k;i++)
for i:=1 to k do if ((x[i]==x[k]) &&
if((x[i]=x[k]) and (a[k][i]==1))
a[k,i]=1)) then return 0;
cont:=false; return 1;
end; }
procedure backrec(k:integer); void backrec(int k){
var i:integer;
begin
if k=n+1 then if(k==n)
tipar(x) tipar(x);
else else
for i:=1 to 4 do for(int i=1;i<=4 ;i++)
begin {
x[k]:=i; x[k]=i;
if cont(x,k) then if (cont(x,k))
backrec(k+1); backrec(k+1);
end }
end; }
29
Generarea irurilor de n
paranteze ce se nchid corect
 Se citete de la tastatur un numr natural n, n 30. S
se genereze i s se afieze pe ecran toate combinaiile
de n paranteze rotunde care se nchid corect.
 De exemplu, pentru n = 4 se obin urmtoarele
combinaii:
(( )), ( )( )
 Pentru n = 6 se obin combinaiile:
((( ))), (()()), ( )( )( ), ( )(( )), (( ))( )

30
 Exist soluii n este par.
 Reprezentarea soluiei: x = (x1, x2,, xn), unde xk
{'(', ')'}
 Notm dif = nr( - nr) la pasul k
 Condiii interne (finale)
dif = 0
dif 0 pentru orice secven {x1, x2,, xk}
 Condiii de continuare
dif 0 doar necesar
dif n k i suficient
 Observaie. n implementarea urmtoare backtracking-ul
este optimal: se avanseaz dac i numai dac suntem
siguri c vom obine cel puin o soluie. Cu alte cuvinte,
condiiile de continuare nu sunt numai necesare, dar i
suficiente.
31
procedure backrec(k:integer); void backrec(int k)
begin {
if(k=n+1) then if(k==n)
tipar(x) tipar(x);
else else
begin {
x[k]:='('; x[k]='(';
dif:=dif+1; dif++;
if(dif <= n-k+1) then if (dif <= n-k)
backrec(k+1); backrec(k+1);
dif:=dif-1; dif--;
x[k]:=')'; x[k]=')';
dif:=dif-1; dif--;
if(dif >= 0) then if (dif >= 0)
backrec(k+1); backrec(k+1);
dif:=dif+1; dif++;
end; }
end; }
if(n mod 2=0) then if (n%2==0)
begin {
dif:=0; dif=0;
backrec(1); backrec(0);
end; }
32
Partiiile unui numr natural
Dat un numr natural n, s se genereze toate partiiile lui
n ca sum de numere pozitive (x1, x2,, xk {1,2,,n}
cu proprietatea x1+ x2 ++ xk = n).

De exemplu, pentru n = 4, partiiile sunt


1+1+1+1, 1+1+2, 1+3, 2+2, 4
Pentru n = 6, partiiile sunt
1+1+1+1+1+1, 1+1+1+1+2, 1+1+1+3, 1+1+2+2,
1+1+4, 1+2+3, 1+5, 2+2+2, 2+4, 3+3, 6

33
 Reprezentarea soluiei: x = (x1, x2,, xk) (stiv de
lungime variabil!), unde xi {1,2,,n}
 Condiii interne (finale)
x1+ x2 ++ xk = n
pentru unicitate: x1 x2 xk
 Condiii de continuare
xk-1 xk (avem xk {xk-1,,n})
x1 + x2 +... + xk n

34
begin void back(){
k:=1; s:=0; int k=0, s=0;
while(k>=1) do while(k>=0){
begin
if(x[k]<n){
if(x[k]<n) then
begin x[k]++; s++;
x[k]:=x[k]+1; s:=s+1; if(s<=n) { //cond.cont.
if (s<=n) if(s==n){ // solutie
then begin tipar(x,k);
if(s=n) then begin s=s-x[k]; k--;
tipar(x,k); //revenire
s:=s-x[k]; }
k:=k-1;
else
end
else begin { //avansare
k:=k+1; k++;
x[k]:=x[k-1]-1; x[k]=x[k-1]-1;
s:=s+x[k]; s+=x[k];
end; }
end }
else begin else {//revenire
s:=s-x[k];
s=s-x[k]; k--;
k:=k-1;
end; }
end; }
end; }
end; } 35
Probleme date la admitere care
se pot rezolva cu metoda
backtracking
1. Generarea unor numere cu proprieti
specificate
2. Generarea produsului cartezian
3. Generarea tuturor soluiilor unei probleme,
pentru a alege dintre acestea o soluie care
minimizeaz sau maximizeaz o expresie

36
Problem (admitere 2012)
Utiliznd metoda backtracking se genereaz toate
numerele cu cte trei cifre impare, cifre care
aparin mulimii {7,8,1,6,2,3}. Primele 4 soluii
generate sunt, n aceast ordine: 777, 771, 773,
717. Cea de a 8-a soluie generat este:
a) 737 b) 788 c) 717 d) 731

{7,8,1,6,2,3} {7,8,1,6,2,3}
Solutia 1: 777 Solutia 5: 711
Solutia 2: 771 Solutia 6: 713
Solutia 3: 773 Solutia 7: 737
Solutia 4: 717 Solutia 8: 731

37
Algoritmul este asemnator cu cel de la aranjamente
var cif: array[1..6] of int n=6, p=3, nrsol = 0,
integer = (7,8,1,6,2,3); x[3];
int cif[]={7,8,1,6,2,3};
procedure tipar(x:stiva); void tipar(int x[])
var i:integer; {
begin nrsol++;
nrsol := nrsol+1; printf("Sol. %d:", nrsol);
write('Sol. ',nrsol,': '); for(int i=0; i<p; i++)
for i:=1 to p do printf("%d", cif[x[i]-1]);
write(cif[x[i]],' '); printf("\n");
writeln; }
end;
function cont(x:stiva; int cont(int x[], int k)
k:integer):boolean; {
begin if (cif[x[k]-1]%2==0)
cont:=true; return 0;
if cif[x[k]] mod 2 = 0 then return 1;
cont:=false; }
end;

38
Problem (admitere 2006)

Reformulare. Se dau vectorii i cu proprietatea S se


genereze toi vectorii cu proprietatea

39
a:array[1..4] of integer=(1,8,1,1); int n=4, nrsol = 0, x[4];
b:array[1..4] of integer=(2,9,2,9); int a[]={1,8,1,1},
b[]={2,9,2,9};
procedure back(); void back()
var k,i:integer; {
begin int k = 0;
for i:=1 to n do for(int i=0; i<n; i++)
x[i]:=a[i]-1; x[i]=a[i]-1;
k:=1; while(k > -1){
while k>0 do begin if (k==n) {
if k=n+1 then tipar(x);
begin k--;
tipar(x); k:=k-1; }
end else
else if (x[k]<b[k]){
if x[k]<b[k] then x[k]++; k++;
begin }
x[k]:=x[k]+1; k:=k+1; else
end {
else begin x[k]=a[k]-1;
x[k]:=a[k]-1; k:=k-1; k--;
end; }
end; }
end; } 40
procedure void backrec(int k){
backrec(k:integer);
var i:integer;
begin
if k=n+1 then if(k==n)
tipar(x) tipar(x);
else else
for i:=a[k] to b[k] do for(int i=a[k];i<=b[k];i++){
begin x[k]=i;
x[k]:=i; backrec(k+1);
backrec(k+1); }
end }
end;

Numrul vectorilor cu proprietatea cerut este

41
Problem (admitere 2011, enun
modificat)
Se d un vector v de n elemente egale cu 1. Prin partiie a
vectorului v nelegem o mprire a vectorului n
subvectori, astfel nct fiecare element al vectorului v
apare exact o dat ntr-unul dintre subvectori. Pentru
fiecare partitie a vectorului v n p subvectori
 , , !" , # , , #!$ , , % , , %!& , se calculeaz
produsul sumelor elementelor din fiecare subvector al
%
partiiei, adic * ( .
a) S se citeasc n, p de la tastatur i s se scrie un
program care determin cel mai mare produs
calculat n acest fel pentru toate partiiile n p
subvectori ale vectorului v.
b) Exist o soluie la punctul a) care s nu calculeze
toate produsele posibile? Justificai.
42
ntrebare
 Se dau n = 11, p=3. Care este cel mai mare produs
%* ( pentru toate partiiile n p subvectori ale
vectorului v?
a) 21
b) 30
c) 48
d) 64
 Observaie: n1 + n2 + + np = n.

43
Exemplu
 n = 11, p = 3: n1 + n2 + n3 = 11
 [ [1,1,1] , [1,1,1,1] , [1,1,1,1] ]
 n1 =3, n2 = 4, n3 = 4, n1n2n3 = 48

n1 n2 n3 Produs
1 1 9 9
1 2 8 16
1 3 7 21

3 3 5 45
3 4 4 48

44
var n,p,nrsol,prod_max:integer; int n, p, nrsol = 0,
nrsol := 0; prod_max := 0; x[20], prod_max=0;

procedure tipar(x:stiva); void tipar(int x[])


var i,prod:integer; {
begin int prod = 1;
prod := 1; nrsol++;
nrsol := nrsol+1; printf("Sol %d: ", nrsol);
write('Solutia ',nrsol,': '); for(int i=0; i<p; i++)
for i:=1 to p do begin {
write(x[i],' '); printf("%d ", x[i]);
prod:=prod*x[i]; prod = prod*x[i];
end; }
write(' are produsul ',prod); printf(" are produsul %d
writeln; \n", prod);
if prod > prod_max then if (prod > prod_max)
prod_max := prod; prod_max = prod;
end; }

45
function cont(x:stiva; int cont(int x[], int k)
k:integer):boolean; {
var s,i:integer; int s = 0;
begin
s := 0; cont:=true; if (k>0)
if k>1 then if (x[k] < x[k-1])
if x[k]<x[k-1] then return 0;
cont:=false;
for i:=1 to k do s:=s+x[i]; for (int i=0; i<=k; i++)
if s>n then s = s + x[i];
cont:=false; return (s<=n);
end; }
function solutie(x:stiva; int solutie(int x[], int k)
k:integer):boolean; {
var s,i:integer;
begin
s := 0; solutie:=true; int s = 0;
if k<>p+1 then if (k!=p)
solutie := false; return false;
for i:=1 to p do for (int i=0; i<p; i++)
s := s + x[i]; s = s + x[i];
if s <> n then return (s==n);
solutie:=false; }
end; 46
procedure back(); void back(){
var k,i:integer;
begin int k = 0;
for i:=1 to p do x[i]:=0; for(int i=0; i<p; i++)
k:=1; x[i]=0;
while k>0 do while(k > -1)
begin {
if solutie(x,k) then if (solutie(x,k))
begin {
tipar(x); tipar(x);
k:=k-1; k--;
end }
else else
if x[k]<n then if(x[k]<n)
begin {
x[k]:=x[k]+1; x[k]++;
if cont(x,k) then if (cont(x,k))
k:=k+1; k++;
end }
else begin else {
x[k]:=0; x[k]=0;
k:=k-1; k--;
end; }
end; }
47
end; }
Exist o soluie la punctul a) care s nu
calculeze toate produsele posibile? Justificai!

Pentru n i p dai notm cu c, r ctul i restul mpririi lui


n la p. Elementele ce vor maximiza produsul sunt:
c, c, , c, c+1, , c+1

de p-r ori de r ori

+,-./
0 %12 30 4 152

48
ntrebare
Se dau n = 26, p=4. Care este cel mai mare produs
%* ( pentru toate partiiile n p subvectori ale
vectorului v?
a) 1375
b) 1820
c) 1764
d) 1728

49
Exerciii propuse
1. Generarea tuturor submulimilor mulimii {1,2, ..., n}.
2. Generarea submulimilor unei mulimi cu elemente
arbitrare {a1,a2, ..., an}.
3. Generarea partiiilor unei mulimi.
4. Se d o sum s i n tipuri de monede avnd valorile a1,
a2, , an lei. Se cer toate modalitile de plat a sumei
s utiliznd tipurile de monede date.
5. S se determine numerele A de n cifre, 
 # !
cu  1,2 , 7
1. . (, care sa fie divizibile cu 2n.

50
V mulumesc!

Succes la examenul de
admitere!

51

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