Sunteți pe pagina 1din 15

Informatica clasa a XI-a - Suport de curs 1

METODA BACKTRACKING – STANDARD

1. Mecanism general

Apare frecvent situaţia în care rezolvarea unei probleme conduce la determinarea unor vectori soluţie
de forma X=(x1, x2,……,xn) în care :
- fiecare componentă a vectorului soluţie aparţine unei mulţimi finite de valori Vi
- există anumite relaţii care trebuie satisfăcute de componentele vectorului, numite condiţii interne,
astfel încât X este soluţie dacă şi numai dacă componentele sale satisfac aceste condiţii interne

Exemplu:
Fie două mulţimi de litere V1={A,B,C} şi V2={M,N}. Se cere să se determine acele perechi (x1,x2) cu
x1V1 şi x2V2 cu proprietatea că dacă x1{A,B} atunci x2N.
Soluţiile care satisfac condiţia impusă sunt : {A,M},{B,M},{C,M},{C,N}.

Produsul cartezian V1xV2x…….Vn se numeşte spaţiul soluţiilor posibile. Soluţiile problemei sunt
acele soluţii posibile care îndeplinesc condiţiile interne.

Exemplu:
Fie un joc Pronosport în care sunt în discuţie doar 4 meciuri. O persoană doreşte să joace, plecând cu
convingerea că în variantele câştigătoare nu pot exista mai mult de două meciuri nule (pronostic 0), iar la ultimul
meci gazdele nu câştigă. Persoana doreşte să găsească toate variantele care îndeplinesc aceste condiţii.
În acestă problemă V1=V2=V3=V4={0,1,2}. Există mai mulţi vectori care îndeplinesc condiţiile interne :
(0,1,2,0),(1,2,1,2),….
O modalitate de rezolvare ar fi să se genereze pe rând cele 34=81 soluţii posibile şi să se aleagă cele
care satisfac condiţiile interne. Această metodă este inacceptabilă pentru că se consumă prea mult timp.
Metoda backtracking evită generarea tuturor soluţiilor posibile, scurtând timpul de lucru.
Componentele vectorului primesc valori în ordinea crescătoare a indicilor. Astfel, xk primeşte valori
numai după ce x1,x2,…….xk-1 au primit valori care nu contrazic condiţiile interne. În plus, valoarea lui xk trebuie
aleasă astfel încât, vectorul soluţie parţial x1,……,xk să îndeplinească şi el anumite condiţii, numite condiţii
de continuare, şi care sunt derivate din condiţiile interne. Astfel, pentru exemplul anterior, dacă x1=x2=0
(meci nul), atunci x3 nu mai poate primi valoarea 0.
Neîndeplinirea condiţiilor de continuare exprimă faptul că oricum am alege în continuare valori pentru
componentele xk+1,…..,xn, nu vom obţine o soluţie. Stabilirea condiţiilor de continuare este foarte importantă, o
alegere bună ducând la o reducere considerabilă a numărului de calcule.
Prin backtracking, orice vector soluţie este construit progresiv, începând cu prima componentă şi
mergând către ultima, cu eventuale reveniri asupra valorilor atribuite anterior. Componentele x1,x2,…….xn iau
valori în mulţimile V1,V2,…….Vn. Prin atribuiri reuşite sau încercări de atribuiri eşuate din cauza nerespectării
condiţiilor de continuare, anumite valori sunt consumate. Pentru o componentă xk din vectorul soluţie, notăm cu
CkVk mulţimea valorilor consumate la momentul curent. Putem descrie metoda backtracking utilizând o
configuraţie de forma :

x1 x2……………xn
C1 C2……………Cn

În cursul aplicării metodei backtracking, o configuraţie poate fi obiectul a patru tipuri de modificări şi anume :

a) Atribuie şi avansează : are loc atunci când pentru xk mai sunt valori neconsumate (CkVk) şi valoarea
aleasă pentru xk (fie ea vk) satisface condiţiile de continuare. În acest caz, xk primeşte valoarea respectivă
care se adaugă la mulţimea valorilor consumate şi se avansează la componenta xk+1 :
xk vk
Ck Ck  {vk}
Kk+1
Informatica clasa a XI-a - Suport de curs 2
b) Încercare eşuată : are loc atunci când pentru xk mai sunt valori neconsumate, dar valoarea aleasă (fie
ea vk) nu satisface condiţiile de continuare. În acest caz, valoarea respectivă se adaugă la mulţimea
valorilor consumate Ck dar nu se avansează la componenta următoare :
Ck Ck  {vk}

c) Revenire : are loc atunci când toate valorile pentru xk au fost consumate (Ck=Vk) şi nu s-a putut avansa la
xk+1 pentru că nu sunt satisfăcute condiţiile de continuare. În acest caz, se anulează valorile consumate
pentru componenta xk şi se revine la componenta xk-1 în încercarea de a-i atribui acesteia o altă valoare
care să permită continuarea construirii vectorului soluţie:
Ck
Kk-1

d) Revenire după construirea unei soluţii : are loc atunci când toate componentele vectorului au
primit valori care satisfac condiţiile interne, adică s-a construit o soluţie. În acest caz se revine la ultima
componentă (xk,k=n) încercând să-i atribuim o nouă valoare (dacă mai există) pentru construirea altor
soluţii.

Condiţia k=n+1 este utilizată în practică pentru a sesiza momentul în care s-a construit o soluţie.
Condiţia k=0 (adică C1=V1,…..,Cn=Vn) este utilizată în practică pentru a sesiza finalul procesului de construire
a soluţiilor, adică încheierea algoritmului backtracking.

Algoritmul corespunzător metodei backtracking este următorul :

*iniţializează mulţimile de valori V1, V2,……,Vn


k=1; Ci= , () i=1,..,n // configuraţia iniţială
cât_timp k>0 // configuraţia nu este finală
dacă k=n+1 // configuraţie de tip soluţie
atunci
reţine soluţia X=(x1,…,xn)
k=k-1 // revenire după construirea unei soluţii
altfel
dacă CkVk // mai sunt valori neconsumate
atunci
alege o valoare vk din (Vk-Ck)
Ck=Ck{vk} //adauga vk la valorile consumate
dacă (x1,…..,xk) satisfac cond. de continuare
atunci
xk=vk // atribuie
k=k+1 // avansează
altfel
// nimic; încercare eşuată
sfârsit_dacă
altfel
Ck= // anulam valorile consumate
k=k-1 // revenire
sfârsit_dacă
sfârsit_dacă
sfârsit_cât_timp
Informatica clasa a XI-a - Suport de curs 3

2. Varianta iterativă standard a metodei backtracking

Programarea algoritmului backtracking se simplifică mult dacă mulţimile în care pot lua valori
componentele vectorului sunt identice cu mulţimea finită S={1,2,….,s} adică cu primele s numere naturale.
Majoritatea problememlor rezolvabile prin backtracking permit o codificare a datelor de intrare astfel încât
acestea să concidă cu primele s numere naturale (inclusiv 0). În acest caz, funcţia care implementează
mecanismul backtracking este :

void Back()
{
int k,i;
k=1;
while(k>0) // mai sunt solutii posibile
if(k==n+1) // am obtinut o solutie
{ Retsol(); k--;}
// revenire dupa constr. unei solutii
else
if(x[k]<s) // mai sunt valori neconsumate
{ x[k]++; // alege urmatoarea valoarea
if(Cont(k)) k++; // atribuie si avanseaza
}
else
{ x[k]=0; k--;}
// anuleaza val.consumate si revine la x[k-1]
}

Funcţia Back apelează:


- funcţia Retsol care reţine soluţia , adică vectorul X (o listează sau o compară cu alte soluţii obţinute
anterior)
- funcţia Cont care care verifică dacă primele k componente ale vectorului soluţie X satisfac condiţiile de
continuare, întorcând valoarea 1 în caz afirmativ şi 0 în caz contrar
Informatica clasa a XI-a - Suport de curs 5

3. Problema reginelor

Să se afişeze pe ecran toate posibilităţile de aranjare a n regine pe o tablă de şah nxn astfel încât
oricare două să nu se atace reciproc. Două regine se atacă reciproc dacă se află pe aceeaşi linie, pe aceeaşi
coloană sau pe aceeaşi diagonală. O poziţie ocupată de o regină va fi reprezentată prin caracterul “ R” , în timp
ce o poziţie liberă va fi reprezentată prin caracterul “*” .
Este evident că vom plasa doar câte o regină pe fiecare linie deoarece două regine aflate pe aceeaşi
linie se vor ataca. Urmează să decidem în ce coloană va fi amplasată regina de pe fiecare linie. Deci
dimensiunea vectorului soluţie X este n (numărul de regine), x[k] fiind coloana în care vom amplasa regina de
pe linia k. Numerotând coloanele cu 1,2,…,n înseamnă că fiecare componentă x[k]{1,2,…n}. Funcţia
Retsol va afişa o amplasare obţinută, iar funcţia Cont va verifica dacă regina de pe linia k, amplasată în
coloana x[k] nu se atacă cu una din reginele amplasate anterior.
Exemplu: pentru n=4, construirea unei soluţii se realizează astfel:

R * * * R * * * R * * * R * * * R * * *
* * * * R * * * * R * * * * R * * * R *
* * * * * * * * * * * * * * * * R * * *
* * * * * * * * * * * * * * * * * * * *
atribuie si încercare încercare atribuie şi încercare
avansează eşuată eşuată avansează eşuată
R * * * R * * * R * * * R * * * R * * *
* * R * * * R * * * R * * * R * * * * R
* R * * * * R * * * * R * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
încercare încercare încercare revenire la k=2 atribuie şi
eşuată eşuată eşuată avansează
R * * * R * * * R * * * R * * * R * * *
* * * R * * * R * * * R * * * R * * * R
R * * * * R * * * R * * * R * * * R * *
* * * * * * * * R * * * * R * * * * R *
încercare atribuie şi încercare încercare încercare
eşuată avansează eşuată eşuată eşuată
R * * * R * * * R * * * R * * * R * * *
* * * R * * * R * * * R * * * R * * * R
* R * * * R * * * * R * * * * R * * * *
* * * R * * * * * * * * * * * * * * * *
încercare revenire la k=3 încercare încercare revenire la k=2
eşuată eşuată eşuată
R * * * * R * * * R * * * R * * * R * *
* * * * * * * * R * * * * R * * * * R *
* * * * * * * * * * * * * * * R * * * *
* * * * * * * * * * * * * * * * * * * *
revenire la k=1 atribuie si încercare încercare încercare
avansează eşuată eşuată eşuată
* R * * * R *
#include<iostream> * * R * * * R * * * R * *
* * * R * * *
#include<math.h> R * * * R * * * R * * * R
* * * * R * *
int x[9],sol,n; * R * * * R * * * R * * *
* * * Retsol()
void * * * * * R * * * * R * * * * R *
{ int i,j; atribuie si
atribuie si încercare încercare atribuie şi
avansează avansează eşuată eşuată avansează
soluţie
Informatica clasa a XI-a - Suport de curs 6

#include<iostream>
#include<math.h>
int x[20],sol,n;
void Retsol()
{ int i,j;
sol++; cout<<"\t Solutia:”<<sol;
for(i=1;i<=n ;i++)
{ for(j=1; j<=n; j++)
if(x[i]==j) cout<<" R";
else cout<<" *";
cout<<"\n";
}
}
int Cont(int k)
{ int i;
for(i=1;i<=k-1;i++)
if(x[k]==x[i] || abs(x[k]-x[i])==k-i)return 0;
return 1;
}
void Back()
{ int i,k=1;
for(i=1;i<=n;i++) x[i]=0;
while(k>0)
if (k==n+1) { Retsol(); k--;}
else
if(x[k]<n)
{ x[k]++;
if (Cont(k)) k++;
}
else
{ x[k]=0; k--;}

}
int main()
{
cout<<“n=”); cin>>n;Back();
}
Informatica clasa a XI-a - Suport de curs 7

4. Generarea aranjamentelor

Să se genereze aranjamentele de n obiecte luate câte k (k,nN*, k<=n<=50).

Un aranjament este un grup de k din cele n obiecte în care contează ordinea. O soluţie va reprezenta
un astfel de grup deci va avea k elemente. Într-un grup poate fi plasat oricare din cele n obiecte, deci
x[pas]{1,2,…….,n}. Într-un aranjament valorile nu se repetă, deci x[pas] este bine ales dacă diferă de
valorile x[1], x[2],…….,x[pas-1] deja plasate în vectorul soluţie.

Exemplu: pentru generarea aranjamentelor de 4 obiecte luate câte 3, în tabelul următor sunt prezentaţi
primii paşi efectuaţi de algoritmul backtracking.

x1 x2 x3 operaţie x1 x2 x3 operaţie
1 - - atribuie şi avansează 1 3 1 încercare eşuată
1 1 - încercare eşuată 1 3 2 atribuie şi avansează
1 2 - atribuie şi avansează 1 3 2 soluţie şi revenire la x[3]
1 2 1 încercare eşuată 1 3 3 încercare eşuată
1 2 2 încercare eşuată 1 3 4 atribuie şi avansează
1 2 3 Atribuie şi avansează 1 3 4 soluţie şi revenire la x[3]
1 2 3 soluţie şi revenire la x[3] 1 3 - revenire la x[2]
1 2 4 atribuie şi avansează 1 4 - atribuie şi avansează
1 2 4 soluţie şi revenire la x[3] 1 4 1 încercare eşuată
1 2 - revenire la x[2] 1 4 2 atribuie şi avansează
1 3 - atribuie şi avansează 1 4 2 soluţie şi revenire la x[3]

#include<iostream>
int x[50],n,k;
void Retsol()
{
// tipareste o solutie
int i;
for(i=1;i<=k;i++) cout<<x[i]<<” ”;
cout<<"\n";
}
int Cont(int pas)
{
// verifica cond. de continuare pentru componenta x[pas]
int i;
for(i=1;i<=pas-1;i++)
if(x[pas]==x[i]) return 0; // valoarea se repeta
return 1;
}
void Back()
{
int i,pas;
for(i=1;i<=k;i++) x[i]=0; // configuratia initiala
pas=1;
while(pas>0)
if(pas==k+1) //am obtinut o solutie
{
Retsol();
pas--; //revenire dupa construirea unei solutii
}
else
Informatica clasa a XI-a - Suport de curs 8
if(x[pas]<n) // mai sunt valori neconsumate
{
x[pas]++; // alegem o valoare
if(Cont(pas)) pas++;
//atribui si avansez
}
else
{
x[pas]=0;
//anulam val. consumate pentru x[k]
pas--;
//revenire la componenta anterioara
}
}
void main()
{

cout<<"n,k="; cin>>n>>k;
Back();
}
Informatica clasa a XI-a - Suport de curs 9

5. Generarea submulţimilor

Afişaţi toate submulţimile mulţimii {1,2,………., n} , pentru n natural nenul , n<=10, citit de la tastatură.

Pentru a rezolva această problemă vom da o nouă semnificaţie vectorului soluţie şi anume :
componenta x[k]=1 dacă elementul k aparţine submulţimii curente şi x[k]=0 in caz contrar. Vectorul soluţie
va avea n elemente binare.

Exemplu: pentru n=3 se vor afişa submulţimile ,3,2,2,3,1,1,3, 1,2, 1,2,3.


Tabelul următor ilustrează evoluţia vectorului soluţie pentru primii paşi.

x1 x2 x3 operaţie x1 x2 x3 operaţie
0 - - atribuie şi avansează 0 1 - revenire la x[2]
0 0 - atribuie şi avansează 0 - - revenire la x[1]
0 0 0 atribuie şi avansează 1 - - atribuie şi avansează
0 0 0 soluţia  şi revenire la x[3] 1 0 - atribuie şi avansează
0 0 1 atribuie şi avansează 1 0 0 atribuie şi avansează
0 0 1 soluţia 3 şi revenire la x[3] 1 0 0 soluţia 1 şi revenire la x[3]
0 1 - atribuie şi avansează 1 0 1 atribuie şi avansează
0 1 0 atribuie şi avansează 1 0 1 soluţia 1,3 şi revenire la x[3]
0 1 0 soluţia 2 şi revenire la x[3] 1 0 - revenire la x[2]
0 1 1 atribuie şi avansează 1 1 - atribuie şi avansează
0 1 1 soluţia 2,3 şi revenire la x[3] 1 1 0 atribuie şi avansează

#include<iostream>
int x[100],n;
void Retsol() // tipareste o submultime
{
int i;
cout<<"{");
for(i=1;i<=n;i++)
if(x[i]) cout<<i<<” ”;
cout<<"\n";
}
void Back()
{
int k;
k=1; x[1]=-1; // configuratia initiala
while(k>0)
if(k==n+1) // am obtinut o solutie
{
Retsol(); // tiparim solutia
k--; // revenire dupa construirea unei solutii
}
else
if(x[k]<1) // mai sunt valori neconsumate
{
x[k]++; // alegem o valoare
k++; // avansam la componenta x[k+1]
x[k]=-1; // configuratia initiala ptr. x[k+1]
}
else
{ x[k]=-1; // anulam valorile consumate;
k--; // revenire la componenta x[k-1]
}
}
void main()
Informatica clasa a XI-a - Suport de curs 10
{ cout<<"n="; cin>>n; Back();}

6. Colorarea hărţii

Se consideră o hartă care cuprinde n ţări din care unele au graniţă comună. Să se coloreze harta utilizând s
culori (s<n) astfel încât oricare două ţări cu graniţă comună să fie colorate diferit.

Pentru a memora relaţia de vecinătate, vom utiliza o matrice binară Anxn în care a[i,j]=1 dacă ţările i
si j au graniţă comună, respectiv a[i,j]=0 în caz contrar. Relaţia de vecinătate fiind reflexivă, matricea A este
simetrică faţă de diagonala principală. O soluţie reprezintă o colorare a ţărilor conform cerinţelor. Elementul
x[k] din vectorul soluţie x va reprezenta culoarea atribuită ţării k. Sunt n ţări, deci vectorul x are n
componente. Sunt disponibile s culori, deci x[k]{1,2,…s} . Ţara k este bine colorată dacă culoarea ei diferă
de culoarea ţărilor vecine deja colorate.

În figura următoare este ilustrată o modalitate de colorare a unei hărţi formată din 6 ţări folosind 4 culori.

Tabelul următor iliustrează evoluţia vectorului de colorare x


pentru harta de mai sus şi culorile numerotate cu 1,2,3,4.

x x x x x x operaţia
1 2 3 4 5 6
1 - - - - - atribuie şi
avansează
1 1 - - - - încercare eşuată
1 2 - - - - atribuie şi
avansează
1 2 1 - - - atribuie şi
avansează
1 2 1 1 - - încercare eşuată
1 2 1 2 - - încercare eşuată
1 2 1 3 - - atribuie şi
avansează
1 2 1 3 1 - încercare eşuată
1 2 1 3 2 - atribuie şi
avansează
1 2 1 3 2 1 încercare eşuată
1 2 1 3 2 2 încercare eşuată
1 2 1 3 2 3 încercare eşuată
1 2 1 3 2 4 atribuie şi
avansează
1 2 1 3 2 4 soluţie şi revenire
la x[6]
#include<iostream>
int a[11][11],x[11],n,s,sol;
void citire() // citeste datele de intrare
{
int i,j;
cout<<"numarul tarilor: "; cin>>n;
cout<<"numarul culorilor: "; cin>>s;
cout<<" introduceti relatiile de vecinatate:\n";
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++)
{
cout<<"tara %d este vecina cu tara “<<i<<”-”<<j<<” [1/0] ?";
Informatica clasa a XI-a - Suport de curs 11
cin>>a[i][j];
a[j][i]=a[i][j];
}
}
void retsol() // tipareste o solutie
{
int i;
sol++; cout<<" solutia de colorare:”<<sol;
cout<<" tara:";
for(i=1;i<=n;i++) cout<<"%3d",i); cout<<"\n";
cout<<" culoarea:"; for(i=1;i<=n;i++) cout<<x[i]<<” ”;
cout<<"\n\n";
}
int cont(int k) // verifica cond. continuare ptr. x[k]
{
int i;
for(i=1;i<=k-1;i++)
if(a[k][i] && x[k]==x[i]) // tari vecine colorate la fel
return 0;
return 1;
}
void back()
{
int k;
k=1;
while(k>0)
if(k==n+1)
{
retsol();
k--;
}
else
if(x[k]<s) // mai sunt valori neconsumate
{
x[k]++;
if(cont(k)) k++; // atribuie si avanseaza
}
else
{
x[k]=0; // anulam valorile consumate
k--; // revenire
}
}
void main()
{
citire(); back();
if(!sol) cout<<"nu exista solutie de colorare!\n";
}
Informatica clasa a XI-a - Suport de curs 12

7. Varianta recursivă a metodei backtracking

Când mulţimile în care pot lua valori componentele vectorului soluţie sunt identice cu mulţimea
S={1,2,….,s} şi vectorul soluţie x are n componente, procedura recursivă care implementează algoritmul
backtracking este :

void Back(int k)
{ int i;
for(i=1;i<=s;i++)
{ x[k]=i; // alegem o valoare
if(Cont(k))
if(k==n)
Retsol(); // retine o solutie
else
Back(k+1) // atribuie si avanseaza
}
}

În acest algoritm, Retsol este o funcţie care reţine soluţia curentă generată (o tipăreşte sau o compară
cu alte soluţii obţinute anterior). Cont este o funcţie care întoarce valoarea 1 dacă valoarea aleasă pentru
componenta x[k] a vectorului satisface condiţiile de continuare, şi 0 în caz contrar. Condiţia k=n este folosită
pentru a sesiza momentul în care s-a completat un vector soluţie. Ciclul for parcurge pe rând valorile posibile
1,2,…..s şi încearcă să atribuie componentei x[k] o valoare din acestă mulţime. Pentru fiecare valoare
aleasă, funcţia Cont verifică dacă sunt satisfăcute condiţiile de continuare. În caz afirmativ, se reia recursiv
acelaşi proces pentru componenta x[k+1] a vectorului. În caz contrar, se încearcă următoarea valoarea
disponibilă din mulţimea 1,2,…….,s. Dacă toate valorile au fost consumate fără a se putea înainta, apelul
recursiv curent se încheie, şi se revine la componenta x[k-1] deoarece, datorită mecanismului recursiv, pe
stiva procesorului se salvează, în ordine, valorile parametrului valoare k. Încheierea unui apel recursiv pentru
valoarea curentă k, presupune recuperarea din stiva procesorului a valorii anterioare (k-1) şi continuarea
algoritmului pentru aceasta, adică atribuirea unei alte valori pentru componenta x[k-1] a vectorului soluţie. În
momentul în care toate apelurile recursive se încheie (stiva procesorului este vidă) , algoritmul backtracking se
încheie.

8. Generarea permutărilor

Să se genereze toate permutările mulţimii {1,2,…,n} pentru n natural nenul dat.

Vectorul soluţie X are n componente, fiecare element x[k] {1,2,….n}. O valoare x[k] este bine
aleasă dacă este diferită de toate valorile x[1],…..,x[k-1] alese anterior, fiindcă într-o permutare valorile
nu se repetă.

În tabelul următor este ilustrată evoluţia vectorului soluţie x pentru n=3.

x1 x2 x3 operaţia x1 x2 x3 operaţia
1 - - atribuie şi avansează 1 3 3 încercare eşuată
1 1 - încercare eşuată 1 3 - revenire la x[2]
1 2 - atribuie şi avansează 1 - - revenire la x[1]
1 2 1 încercare eşuată 2 - - atribuie şi avansează
1 2 2 încercare eşuată 2 1 - atribuie şi avansează
1 2 3 atribuie 2 1 1 încercare eşuată
Informatica clasa a XI-a - Suport de curs 13
1 2 3 soluţie şi continuă x[3] 2 1 2 încercare eşuată
1 2 - revenire la x[2] 2 1 3 atribuie
1 3 - atribuie şi avansează 2 1 3 soluţie şi continuă cu x[3]
1 3 1 încercare eşuată 2 1 - revenire la x[2]
1 3 2 atribuie 2 2 - încercare eşuată
1 3 2 soluţie şi continuă cu x[3] 2 3 - atribuie şi avansează

#include<iostream>
int x[11],n;
void Retsol()
{
int i;
for(i=1;i<=n;i++) cout<<x[i]<<” ”;
cout<<"\n";
}
int Cont(int k)
{
int i;
for(i=1;i<=k-1;i++)
if(x[k]==x[i]) return 0;
return 1;
}
void Back(int k)
{
int i;
for(i=1;i<=n;i++)
{ x[k]=i;
if(Cont(k))
if(k==n)
Retsol();
else
Back(k+1);
}
}
void main()
{
cout<<"n="; cin>>n; Back(1);
}

9. Generarea permutărilor

Să se genereze toate permutările mulţimii {1,2,…,n} pentru n natural nenul dat.

Vectorul soluţie X are n componente, fiecare element x[k] {1,2,….n}. O valoare x[k] este bine
aleasă dacă este diferită de toate valorile x[1],…..,x[k-1] alese anterior, fiindcă într-o permutare valorile
nu se repetă.

În tabelul următor este ilustrată evoluţia vectorului soluţie x pentru n=3.

x1 x2 x3 operaţia x1 x2 x3 operaţia
1 - - atribuie şi avansează 1 3 3 încercare eşuată
1 1 - încercare eşuată 1 3 - revenire la x[2]
1 2 - atribuie şi avansează 1 - - revenire la x[1]
1 2 1 încercare eşuată 2 - - atribuie şi avansează
1 2 2 încercare eşuată 2 1 - atribuie şi avansează
Informatica clasa a XI-a - Suport de curs 14
1 2 3 atribuie 2 1 1 încercare eşuată
1 2 3 soluţie şi continuă x[3] 2 1 2 încercare eşuată
1 2 - revenire la x[2] 2 1 3 atribuie
1 3 - atribuie şi avansează 2 1 3 soluţie şi continuă cu x[3]
1 3 1 încercare eşuată 2 1 - revenire la x[2]
1 3 2 atribuie 2 2 - încercare eşuată
1 3 2 soluţie şi continuă cu x[3] 2 3 - atribuie şi avansează

#include<iostream>
int x[11],n;
void Retsol()
{
int i;
for(i=1;i<=n;i++) cout<<x[i]<<” ”;
cout<<"\n";
}
int Cont(int k)
{
int i;
for(i=1;i<=k-1;i++)
if(x[k]==x[i]) return 0;
return 1;
}
void Back(int k)
{
int i;
for(i=1;i<=n;i++)
{ x[k]=i;
if(Cont(k))
if(k==n)
Retsol();
else
Back(k+1);
}
}
void main()
{
cout<<"n="; cin>>n; Back(1);
}

10. Rearanjarea persoanelor


Un grup de n persoane sunt aşezate pe un rând de scaune. Între oricare doi vecini izbucnesc conflicte de
interese astfel încât, persoanele îşi schimbă aşezarea. Să se determine toate posibilităţile de reaşezare a
persoanelor astfel încât, între oricare doi vecini din varianta iniţială să existe una sau două alte persoane.

Considerăm că iniţial persoanele sunt asezate pe scaune în ordinea 1,2,...,n. Într-o nouă aşezare,
x[k] va fi persoana asezata pe scaunul k. Persoana (oricare din mulţimea 1,2,….,n) este bine alesă dacă
între ea şi persoana x[k-1] (de pe scaunul alăturat) există 1 sau 2 alte persoane şi, desigur, persoana
respectivă nu a fost deja aşezată pe un scaun. Un vector soluţie x va reprezenta o aşezare obţinută în acest
mod şi va avea n componente.

#include<iostream>
#include<math.h>
int x[21],n,sol;
void Retsol()
{
int i;
Informatica clasa a XI-a - Suport de curs 15
sol++;
for(i=1;i<=n;i++) cout<<x[i]<<” ”;
cout<<"\n";
}
int Cont(int k)
{
int i;
if(k==1) return 1;
// prima componenta este totdeauna corecta
if(abs(x[k]-x[k-1])<2 || abs(x[k]-x[k-1])>3) return 0;
// intre x[k] si x[k-1] nu sunt 1 sau 2 persoane
for(i=1;i<=k-1;i++)
if(x[k]==x[i]) // persoana s-a asezat deja pe un scaun
return 0;
return 1;
}
void Back(int k)
{
int i;
for(i=1;i<=n;i++)
{
x[k]=i; //alegem persoana care se aseaza pe scaunul k
if(Cont(k))
if(k==n)
Retsol(); //tiparim o solutie de asezare
else
Back(k+1); // trecem la scaunul urmator
}
}
void main()
{
cout<<"n="; cin>>n; Back(1);
if(!sol) cout<<"nu exista solutii de asezare!";
}

11. Aşezarea turelor pe tabla de şah

Se citeşte de la tastatură un număr natural nenul n (n<=14) care reprezintă dimensiunea unei table de şah. Să
se genereze toate modalităţile de aşezare pe tabla de şah a n ture, astfel încât oricare două să nu se atace
reciproc (două ture se atacă dacă sunt pe aceeaşi linie sau pe aceeaşi coloană).

Fiecare linie a tablei de şah va conţine o tură; la fel şi fiecare coloană. Vectorul soluţie x va reprezenta o
amplasare a celor n ture. Deoarece pe fiecare linie nu poate fi decât o singură tură, un element x[k] din
vectorul soluţie va reprezenta coloana în care am amplasat tura de pe linia k. Numerotând coloanele cu 1,2,
……,n, elementul x[k] va lua valori în acestă mulţime.Tura de pe linia k este bine amplasată dacă nu se află în
aceeaşi coloană cu o altă tură amplasată anterior.
Practic, problema se reduce la generarea permutărilor de n obiecte (coloanele tablei de şah), o
permutare reprezentând o soluţie de aranjare a turelor.

În figura următoare este ilustrată o soluţie de aşezare a turelor pe tabla de şah pentru n=8.

* T * * * * * *
T * * * * * * *
* * * T * * * *
* * T * * * * *
#include<iostream>
int * * * * T * * * x[15],n;
* * * * * * * T
* * * * * T * *
* * * * * * T *
Informatica clasa a XI-a - Suport de curs 16
void Retsol()
{
int i,j;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
if(x[i]==j)
cout<<"T";
else
cout<<".";
cout<<"\n";
}
cout<<"\n"); getchar();
}
int Cont(int k)
{
int i;
for(i=1;i<=k-1;i++)
if(x[k]==x[i]) // doua ture in aceeasi coloana
return 0;
return 1;
}
void Back(int k)
{
int i;
for(i=1;i<=n;i++)
{
x[k]=i; // plasam tura din linia k in coloana i
if(Cont(k))
if(k==n)
Retsol(); // tiparim o solutie
else
Back(k+1); // trecem la linia urmatoare
}
}
void main()
{
cout<<"n="; cin>>n; Back(1);
}

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