Sunteți pe pagina 1din 18

Metoda BackTracking

Metoda backtracking se aplică problemelor în care soluţia se poate prezenta sub


forma unui vector x = {x1 , x2 ,..., xn } Î S = S1xS 2 x...xSn , unde Si sunt mulţimi finite. Cerinţa
problemei este, de obicei, găsirea tuturor soluţiilor posibile, care satisfac anumite condiţii
specifice problemei. S reprezintă spaţiul tuturor soluţiilor posibile iar condiţiile pe care o
soluţie corectă trebuie să le indeplinească vor fi notate cu F ( x1 , x2 ,..., xn ) şi reprezintă
condiţii interne.
Metoda evită generarea tuturor soluţiilor posibile. Se va căuta obţinerea unei
soluţii prin alegerea succesivă de elemente din mulţimile S1 , S 2 , …, Sn . Astfel, la pasul

k, se va alege un element xk Î S k . Înainte de a trece la pasul k+1, se verifică dacă sunt


satisfăcute condiţiile de continuare, derivate din condiţiile interne F .
În cazul în care pentru o valoare xk aleasă, condiţiile de continuare nu sunt

satisfăcute, se va alege o altă valoare din mulţimea Sk , până cand fie se va găsi o valoare
pentru care condiţiile de continuare sunt satisfăcute, fie se epuizează toate elementele
mulţimii S k .
În cazul în care se găseşte un element xk convenabil, se trece la pasul k+1. Dacă

pentru toate elementele mulţimii S k condiţiile interne nu sunt satisfăcute, se va reveni la

pasul anterior (k-1), în care se va renunta la valoarea xk - 1 aleasă şi se va căuta alegerea


unei alte valori.
Algoritmul poate fi realizat în două versiuni: o versiune recursivă şi una
nerecursivă.

Algoritmul general al problemei:


S = {vali,…, valf}

int k =1; x[k] = vali-1;


while (k>0) { if (x[k]< valf) {x[k] + +;
if(conditii(k) = =1) if (solutie(k)) afisare(k);
else { k ++;
x[k] = vali-1;
};
};

1
else k --;
}
Problema 1: să se genereze toate permutările mulţimii A = { 1,2, ..., n}.

# include<iostream.h>
int n, x[100];
int cond (int k)
{
int i;
for(i=1;i<=k-1;i++) if (x[k] = =x[i]) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<x[i]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) if (k= =n) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
cin>> n;
BT ( );
}

2
Problema 1’: să se genereze recursiv toate permutările mulţimii A = { 1,2, ..., n}.

Obs: deoarece după completarea componentei k problema se reduce la una similară de


completare a componentei k+1 cu una dintre valorile valide, tehnica backtracking poate fi
descrisă recursiv.

# include<iostream.h>
int n, x[100];
int cond (int k)
{
int i;
for(i=1;i<=k-1;i++) if (x[k] = =x[i]) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<x[i]<<”_” ;
cout<<endl;
}
void perm_rec(int k)
{
if(k= =n+1) afisare(k-1);
else for(int j=1;j<=n;j++) {
x[k]=j;
if(cond(k)= =1) perm_rec(k+1);
};
}
void main( )
{
cin>> n;
perm_rec(1);
}

3
Problema 2: Se dă un vector v cu n elemente. Să se genereze toate permutările acestor
elemente.

# include<iostream.h>
int n, x[100], v[100];
void citire( )
{
int i; cin>> n;
for(i=1;i<=n;i++) cin>>v[i];
}
int cond (int k)
{
int i;
for(i=1;i<=k-1;i++) if (x[k] = =x[i]) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<v[x[i]]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) if (k= =n) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
citire ( );
BT ( );
}

4
Problema 3: să se genereze toate permutările mulţimii A = { 1,2, ..., n} a.î. în orice
permutare, elementele vecine 2 câte 2 să nu fie consecutive.

# include<iostream.h>
int n, x[100];
int cond (int k)
{
int i;
for(i=1;i<=k-1;i++) if (x[k] = =x[i]) return 0;
if(abs(x[k] – x[k-1])<=1 && k>1) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<x[i]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) if (k= =n) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
cin>> n;
BT ( );
}

5
Problema 4: să se genereze toate aranjamentele de n elemente luate câte p pentru
mulţimea A = { 1,2, ..., n}.

indicaţie: idem permutări, doar că mai citim şi pe p, iar în procedura BT afişarea o facem
dacă k este egal cu p.

# include<iostream.h>
int n, p, x[100];
int cond (int k)
{
int i;
for(i=1;i<=k-1;i++) if (x[k] = =x[i]) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<x[i]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) if (k= =p) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
cin>> n;
cin>> p;
BT ( );
}

6
Problema 5: se dau n elemente întregi. Să se afle toate aranjările a m elemente din cele n

# include<iostream.h>
int n, m, x[100], v[100];
void citire( )
{
int i; cin>> n;
for(i=1;i<=n;i++) cin>>v[i];
}
int cond (int k)
{
int i;
for(i=1;i<=k-1;i++) if (x[k] = =x[i]) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<v[x[i]]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) if (k= =m) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
citire( );
cin>> n;
cin>> p;
BT ( );
}

7
Problema 6: să se genereze toate combinările de n elemente luate câte p pentru mulţimea
A = { 1,2, ..., n}.

De exemplu, pentru n =3, p=2 : 1 2 13 23


Se observă că elementele în cadrul unei soluţii sunt în ordine crescătoare şi atunci în
cadrul funcţiei cond (k) trebuie pusă condiţia x[k] > x[k-1]

# include<iostream.h>
int n, p, x[100];
int cond (int k)
{
if( k>1 && x[k]<=x[k-1] ) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<x[i]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) if (k= =p) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
cin>> n;
cin>> p;
BT ( );
}

8
Problema 7: se dau n persoane prin nume. Să se formeze echipe de câte p persoane.

# include<iostream.h>
# include<stdio.h>
int n, p, x[100];
char v[100][100];
void citire( )
{
int i; cin>> n>>p;
for(i=1;i<=n;i++) gets(v[i]);
}

int cond (int k)


{
if( k>1 && x[k]<=x[k-1] ) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<v[x[i]]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) if (k= =p) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
citire ( );
BT ( );
}

9
Problema 8: Să se genereze toate submulţimile mulţimii {1, 2, ...., n}.

Exemplu: n=3: A={1, 2, 3}.


1 1, 2 1, 2, 3
2 1, 3
3 2, 3

Se observă că :
- elementele în cadrul unei soluţii sunt în ordine crescătoare şi atunci în cadrul funcţiei
cond (k) trebuie pusă condiţia x[k] > x[k-1]
- deoarece atunci când sunt verificate condiţiile de continuare avem deja o soluţie, aceasta
se afişează direct

# include<iostream.h>
int n, x[100];
int cond (int k)
{
if( k>1 && x[k]<=x[k-1] ) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<x[i]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) {
afisare(k);
k++; x[k]=0;
}
}
else k--;
}
}
void main( )
{
cin>> n;
BT ( );
}

10
Problema 9: Se dau n produse prin numele lor.Să se genereze toate submulţimile de
produse.

# include<iostream.h>
# include<stdio.h>
int n, x[100];
char v[100][100];
int cond (int k)
{
if( k>1 && x[k]<=x[k-1] ) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<v[x[i]]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) {
afisare(k);
k++; x[k]=0;
}
}
else k--;
}
}
void main( )
{
cin>> n;
int i;
for(i=1;i<=n;i++) gets(v[i]);
BT ( );
}

11
Problema 10:se dă un număr natural n. Să se afişeze toate numerele formate din cifre
distincte din n.
Exemplu: n=2324 cifre distincte 3: {2,3,4} 2, 3, 4, 23, 32, 24, 42, 34, 43, 234, ...

Indicatie:
- se formează un vector v (cu m poziţii) din cifrele numărului n.
- soluţiile x[1], ... iau valori de la 1 la m (poziţiile din vectorul v).
- pentru i=1,m aplic BT(i) prin care generez v[x[1]],..., v[x[i]]

# include<iostream.h>
int n, x[100], v[100];
void citire( )
{
int i,c; cin>> n; m=0;
while(n!=0){
c=n%10; n=n/10; b=0;
for(i=1;i<=m;i++) if(c = = v[i]) b=1; generam vectorul v
if (b = = 0) { m++; v[m] = c}
}
}
int cond (int k)
{
for(int i=1;i<=k-1;i++) if (x[k] = =x[i]) return 0;
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<v[x[i]]<<”_” ;
cout<<endl;
}
void BT(int p )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < m) {
x[k]++;
if (cond(k) = =1) if (k= =p) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
citire ( );
for (int i=1;i<=m;i++) BT (i);
}

12
Problema 11 (problema celor n dame): pe o tablă de şah de dimensiune n x n trebuie
aşezate n dame a î. ele să nu se ia (să nu se întâlnească pe linie, coloană sau diagonală).

Algoritmul:
- pe fiecare linie se va poziţiona câte o damă , rezultă că soluţia se poate reprezenta sub
forma unui vector x[1], ..., x[n], unde x[i] = coloana damei i, deci x[i] {1, 2, ..., n}.
- condiţiile de continuare sunt reprezentate de faptul că damele nu trebuie să se ia una pe
alta : - pe coloană : pt. i ≠ j x[i] ≠ x[j]
- pe diagonală: | i-j | ≠ | x[i] – x[j] |

# include<iostream.h>
# include <math.h>
int n, x[100];
char a[100][100];
int cond (int k)
{
int i;
for(i=1;i<=k-1;i++) if (x[k] = =x[i]) return 0; // nu se ataca pe col.
for(i=1;i<=k-1;i++) if ( abs(k-i) = = abs( x[k] – x[i] )) return 0; // nu se ataca pe diag.
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++) a[i][j] = ’*’;
for(int i=1;i<=k;i++) a[i][x[i]] = ’D’
for(int i=1;i<=k;i++) {
for(int j=1;j<=k;j++) cout<<a[i][j]<<”_” ;
cout<<endl;
}
}
void BT( )
{
int k; k=1; x[k]=0;
while (k>0) {
if (x[k] < n) {
x[k]++;
if (cond(k) = =1) if (k= =n) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
cin>> n;
BT ( );}

13
Problema 11’ (problema celor n dame-recursiv): pe o tablă de şah de dimensiune n x n
trebuie aşezate n dame a î. ele să nu se ia (să nu se întâlnească pe linie, coloană sau
diagonală).

Algoritmul:
- pe fiecare linie se va poziţiona câte o damă , rezultă că soluţia se poate reprezenta sub
forma unui vector x[1], ..., x[n], unde x[i] = coloana damei i, deci x[i] {1, 2, ..., n}.
- condiţiile de continuare sunt reprezentate de faptul că damele nu trebuie să se ia una pe
alta : - pe coloană : pt. i ≠ j x[i] ≠ x[j]
- pe diagonală: | i-j | ≠ | x[i] – x[j] |

# include<iostream.h>
# include <math.h>
int n, x[100];
char a[100][100];
int cond (int k)
{
int i;
for(i=1;i<=k-1;i++) if (x[k] = =x[i]) return 0; // nu se ataca pe col.
for(i=1;i<=k-1;i++) if ( abs(k-i) = = abs( x[k] – x[i] )) return 0; // nu se ataca pe diag.
return 1;
}
void afisare(int k)
{
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++) a[i][j] = ’*’;
for(int i=1;i<=k;i++) a[i][x[i]] = ’D’
for(int i=1;i<=k;i++) {
for(int j=1;j<=k;j++) cout<<a[i][j]<<”_” ;
cout<<endl;
}
}
void dame_rec(int k)
{
if(k= =n+1) afisare(k-1);
else for(int j=1;j<=n;j++) {
x[k]=j;
if(cond(k)= =1) dame_rec(k+1);
};
}
void main( )
{
cin>> n;
dame_rec(1);
}

14
Problema 12 (problema colorării hărţilor): fiind dată o hartă cu n ţări, se cere o soluţie
de colorare a hărţii utilizând maxim 4 culori a.î. două ţări cu frontieră comună să fie
colorate diferit.

Algoritmul:
- definim o matrice (matricea de adiacenţă): a[i][j] = 1, dacă ţara i e vecină cu ţara j
0, altfel
- cu k notăm ţara, iar x[k] reprezintă culoarea asociată.
- condiţiile de continuare sunt reprezentate de faptul că două ţări cu frontieră comună
trebuie să fie colorate diferit: dacă a[i][j]=1 x[i] ≠ x[j]

# include<iostream.h>
int n, x[100], a[100][100];
void citire ( )
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) cin>>a[i][j];
}
int cond (int k)
{
int i;
for(i=1;i<=k-1;i++) if (a[k][i] = =1 && x[k] = = x[i]) return 0;
return 1;
}
void afisare( )
{
int i;
for(i=1;i<=n;i++) cout<<”ţara”<<i<<”are culoarea”<<x[i]<<endl ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < 4) {
x[k]++;
if (cond(k) = =1) if (k= =n) afisare( );
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
citire ( );
BT ( );}

15
Problema 13 (generarea partiţiilor unui număr natural n): se citeşte un nr. natural n.
Să se tipărească toate modurile de escompunere a lui ca sumă de numere naturale.

Exemplu: n=4 4 31 22 13 211 121 112 1111

Se observă că : 1« x[1] « n
1« x[2] « n-1
...........................
1« x[k] « n-k+1

# include<iostream.h>
int n, x[100];
int cond (int k)
{
int i, S=0;
for(i=1;i<=k;i++) S=S+x[i];
if (S= =n) return 1;
else return 0;
}
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<x[i]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < n-k+1) {
x[k]++;
if (cond(k) = =1) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
cin>> n;
BT ( );
}

16
Problema 14 ( produsul cartezian a n mulţimi): se dau mulţimile A1, A2, ..., An, unde
Ai = {1, 2, ..., vi}, i=1,n. Se cere produsul cartezian al celor n mulţimi.

Algoritmul:
- se citesc n, un vector v[n], unde v[i] = nr. de elemente din Ai.
- orice element x[k] este valid
- limita superioră a lui x[k] nu mai este n, ci v[k]

# include<iostream.h>
int n, x[100], v[100];
void afisare(int k)
{
for(int i=1;i<=k;i++) cout<<x[i]<<”_” ;
cout<<endl;
}
void BT( )
{
int k;
k=1; x[k]=0;
while (k>0) {
if (x[k] < v[k]) {
x[k]++;
if (k= =n) afisare(k);
else { k++; x[k]=0;}
}
else k--;
}
}
void main( )
{
int i;
cin>> n;
for(i=1;i<=n;i++) cin>>v[i];
BT ( );
}

17
Problema 15: se dă un număr natural n par. Să se determine toate şirurile de n paranteze
care se închid corect.
Exemplu : pentru n = 6: ((( ))) () (( )) (( )) () () () () (( )( ))

să se genereze partiţiile mulţimii A= {1, 2, ..., n}.

Trebuie să găsim submulţimi ale lui A a. î. intersectate 2 câte 2 dau mulţimea vidă şi
reunite toate, dau mulţimea A.

Exemplu: n=3 A={1,2,3} avem:


{1} {2} {3}
{1} {2,3}
{2} {1,3}
{3} {1,2}
{1,2,3}

18