Sunteți pe pagina 1din 48

68

3. METODA BATRACKING

3. METODA BACKTRACKING
3.1. Descrierea general a metodei
Deseori n practic apar probleme care implic alegerea unor soluii optime
dintr-un spaiu extrem de vast de soluii posibile.
Un teoretician pur ar rspunde: nici o problem! construim toate soluiile
posibile i le alegem apoi pe cele optime! Dar este realist o astfel de abordare?
S analizm un caz foarte simplu: s presupunem c problema noastr implic
selectarea unei mulimi de n elemente care trebuie s ndeplineasc anumite
condiii. Pentru fiecare element i presupunem c exist pi posibiliti de alegere.
A genera toate soluiile posibile nseamn de fapt a genera toate elementele
produsului cartezian {1, 2, ..., p1}x{1, 2, ..., p2}x...x{1, 2, ..., pn}. Acest
produs cartezian are p1xp2x...xpn elemente. Chiar dac vom considera c pi=2,
pentru orice i de la 1 la n tot obinem 2n soluii posibile. E mult? S evalum cu
aproximaie timpul de execuie a unui program bazat pe un astfel de algoritm,
presupunnd c dispunem de un calculator care execut un miliard de operaii pe
secund (109 operaii).
n

Timp de execuie

40

109 secunde

50

31 ore

100

41013 ani

E puin probabil s putem atepta att!


Prin urmare trebuie s abordm n alt mod astfel de probleme! O idee ar fi s
procedm ca n multe situaii din viaa de zi cu zi. S ne gndim la modul n care
un copil rezolv un puzzle. Copilul nu face toate combinaiile posibile de piese
pentru ca apoi s le compare cu modelul pe care vrea s l obin. El va lua mai
nti o pies. Va cuta apoi n mulimea de piese rmase una care s se potriveasc
la cea pe care o are, apoi nc una, .a.m.d. Dac la un moment dat se blocheaz
(nu mai gsete nici o pies n cele rmase care s se potriveasc), el nu distruge tot
ce a construit ca s o ia de la nceput. Va ndeprta mai nti ultima pies pe care a
pus-o i va cuta o alternativ (o alt pies care s-ar potrivi n locul ei). Dac
gsete, continu construcia cu noua pies aleas. Dac nu gsete, se mai ntoarce
un pas i ndeprteaz i penultima pies pe care a pus-o, cutnd apoi o alt
variant. Procedeul continu pn cnd obine modelul dorit.

3. METODA BACKTRACKING

69

Observai c pe parcursul construciei, copilul face anumite verificri (se


potrivete piesa aici? m poate conduce la modelul dorit?), eliminnd astfel foarte
multe dintre soluiile posibile. Cu alte cuvinte, cutarea nu este exhaustiv.
Un alt aspect semnificativ este faptul c se fac reveniri. Dac la un moment dat
nu mai poate continua construcia, copilul revine la pasul precedent, ndeprteaz
piesa utilizat i ncearc s o nlocuiasc, dac este posibil. Dac nu este posibil,
face reveniri succesive, pn cnd gsete o pies pe care o poate nlocui i apoi
continu construcia. Acest mod de abordare se bazeaz pe principiul ncerc aa,
dac nu merge m ntorc i ncerc o alt variant!
Fr s tie, copilul din exemplu a aplicat metoda backtracking. Numele
metodei este semnificativ1 i s-ar putea traduce prin a o lua napoi pe urme sau,
cu aproximaie, prin cutare cu revenire.
S descriem acum ntr-un mod mai general metoda backtracking. n variant
elementar, considerm c soluia problemei pe care trebuie s o rezolvm se poate
reprezenta ca un vector x=(x0, x1, , xn-1). Fiecare component xi a vectorului
poate lua valori ntr-o anumit mulime Si (i=0, n-1). Produsul cartezian
S0xS1x...xSn-1 se numete spaiul soluiilor posibile.
Problemele care se rezolv prin backtracking nu impun generarea tuturor
soluiilor posibile (generare exhaustiv), ci doar generarea acelor soluii care
ndeplinesc anumite condiii, specifice problemei, denumite condiii interne.
Soluiile posibile care respect condiiile interne sunt denumite soluii rezultat.
Unele probleme impun obinerea unei singure soluii rezultat i anume cea care
ndeplinete o anumit condiie de optim. Aceasta este denumit soluie optim.
Pentru a evita generarea tuturor soluiilor posibile, metoda backtracking atribuie
pe rnd valori elementelor vectorului x. Mai exact, componenta xk primete o
valoare numai n cazul n care componentele x0, x1, ..., xk-1 au primit deja valori.
n acest caz, componentei xk i se atribuie pe rnd acele valori posibile (valori din
mulimea Sk) care ndeplinesc condiiile de continuare. Condiiile de continuare
sunt condiii derivate din condiiile interne, care stabilesc dac pentru o anumit
valoare pentru xk are sau nu sens s continum construcia soluiei. Spunem c o
anumit valoare pentru xk nu ndeplinete condiiile interne dac oricum am atribui
valori componentelor xk+1, ..., xn-1 nu obinem o soluie rezultat (soluie care s
respecte condiiile interne).
Dup atribuirea unei valori posibile care respect condiiile interne componentei
xk se poate continua construcia soluiei n mod recursiv (de data aceasta sunt
fixate k+1 poziii).

1. n limba englez back nseamn napoi, iar track nseamn urm.

70

3. METODA BATRACKING

Pentru a descrie formatul general al metodei backtracking vom utiliza o funcie


BKT(). Considerm c n, numrul de componente ale vectorului, i vectorul x
sunt variabile globale.
void BKT (int k)
{//cand apelam functia BKT cu parametrul k presupunem ca
//pozitiile 0,1,,k-1 din vectorul x sunt fixate
Element MC[]; int nc;
//tipul elementelor din MC depinde de problema concret
if (k==n)
//solutia este completa
Prelucrare_Solutie();
else
//continuam generarea
{Candidat(MC, nc, k);
/*functia Candidat retine in vectorul MC cele nc elemente
din multimea Sk care respecta conditiile de continuare*/
for (int i=0; i<nc; i++)
{x[k]= MC[i];
//extrag un candidat din MC
BKT(k+1);}
//apel recursiv
}
}

Din descrierea general a metodei backtracking nu reiese explicit unde intervine


revenirea. Pentru aceasta trebuie s ne gndim la modul de realizare a recursivitii.
La fiecare apel recursiv se memoreaz pe stiv valorile variabilelor locale i
valoarea parametrului. La ncheierea unui apel recursiv, se elibereaz zona de
memorie alocat pe stiv i se revine la apelul precedent.
Pentru a nelege mai bine modul de funcionare a acestei metode s analizm
urmtoarea problem.

Problema reginelor
S se plaseze n regine pe o tabl de ah de dimensiune nxn astfel nct oricare
dou regine s nu se atace.
Reprezentarea informaiilor
Pentru ca dou regine s nu se atace ele nu trebuie s fie situate pe aceeai linie,
pe aceeai coloan sau pe aceeai diagonal. Cum numrul de regine este egal cu
dimensiunea tablei de ah, deducem c pe fiecare linie trebuie plasat o regin.
Deci, pentru ca poziia reginelor s fie complet determinat, este suficient s
reinem pentru fiecare linie coloana n care este plasat regina. Pentru aceasta vom
utiliza un vector C, cu n componente avnd urmtoarea semnificaie:
C[i] reprezint coloana n care este plasat regina de pe linia i.

3. METODA BACKTRACKING

71

Condiii interne
1. C[i]{0,1,,n-1}, i{0,1,,n-1}
(elementele vectorului C sunt indici de coloane)
2. C[i]C[j], ij, i,j{0,1,,n-1}
(dou regine nu pot fi plasate pe aceeai coloan)
3. |C[i]-C[j]||i-j|, ij, i,j{0,1,,n}
(dou regine nu pot fi plasate pe aceeai diagonal).
#include <iostream.h>
#include <math.h>
#include <conio.h>
int n, NrSol, C[30];
void Plaseaza_Regina(int);
int main ()
{ cout << "n= "; cin >> n;
Plaseaza_Regina(0); return 0; }
void Afisare()
{int i, j;
cout<<"Solutia nr. "<< ++NrSol<<endl;
for (i=0; i<n; i++)
{for (j=0; j<n; j++)
if (j==C[i]) cout<<" * ";
else cout<<" o ";
cout<<endl;}
cout<<endl; getch(); }
void Plaseaza_Regina(int k)
{/*cand apelam functia Plaseaza_Regina cu parametrul k am
plasat deja regine pe liniile 0,1,...,k-1 */
int i, j, ok;
if (k==n)
//am obtinut o solutie
Afisare();
//prelucrarea solutiei consta in afisare
else
//trebuie sa mai plasam regine pe liniile k,k+1,...,n-1
for (i=0; i<n; i++)
//verific daca pot plasa regina de pe linia k in coloana i
{for (ok=1, j=0; j<k; j++)
if (C[j]==i || abs(C[j]-i)==(k-j)) ok=0;
/*regina s-ar gasi pe aceeasi coloana sau aceeasi diagonala
cu o regina deja plasata */
if (ok)
//valoarea i respecta conditiile interne
{C[k]=i; //i este un candidat, il extrag imediat
Plaseaza_Regina(k+1);}}
}

72

3. METODA BATRACKING

3.3. Aplicaii
Plata unei sume cu monede de valori date
Avnd la dispoziie n sculei cu monede, fiecare scule coninnd monede de
aceeai valoare, s se afieze toate modalitile de a plti o sum dat S folosind
numai monedele din sculei.
De exemplu, s presupunem c trebuie s achitm suma S=100 i avem n=3
sculei de monede. n primul scule se gsesc 6 monede cu valoarea 3, n al
doilea scule se gsesc 4 monede cu valoarea 7, iar n ultimul scule sunt 14
monede cu valoarea 5. Programul va afia n fiierul de ieire (denumit
suma.out) cele dou soluii posibile de plat astfel:
Solutia nr. 1
3 monede cu valoarea 3
3 monede cu valoarea 7
14 monede cu valoarea 5
Solutia nr. 2
4 monede cu valoarea 3
4 monede cu valoarea 7
12 monede cu valoarea 5

Reprezentarea informaiilor
Vom reine ntr-un vector V cu n componente valorile monedelor din cei n
sculei, iar ntr-un alt vector M vom reine multiplicitile, adic numrul de
monede din fiecare scule n parte.
Soluiile vor fi generate ntr-un vector P, cu n componente avnd semnificaia:
P[i] numrul de monede din sculeul i folosite pentru plata sumei S,
i{0,1,,n-1}.
Condiii interne
1. P[i]{0,1,,M[i]}, i{0,1,,n-1}
(din sculeul i se pot folosi cel mult M[i] monede);
2. P[0]V[0]+P[1]V[1]++P[n-1]V[n-1]=S
(valoarea total a monedelor selectate trebuie s fie egal cu suma S).
Pentru a genera soluiile vom utiliza o funcie recursiv Plata(). Cnd apelm
funcia Plata(k), am stabilit numrul de monede din sculeii 0, 1, 2, ..., k-1.
Pentru a completa soluia, ocupm mai nti poziia k din vectorul P i apoi apelm
recursiv funcia Plata(k+1). Pe poziia k poate fi plasat orice numr natural
care reprezint numrul de monede selectate din sacul k (deci acest numr trebuie
s fie M[k]) i n plus valoarea total a monedelor selectate s nu depeasc S.

3. METODA BACKTRACKING

73

#include <fstream.h>
#define NrMaxMonede 20
unsigned V[NrMaxMonede], M[NrMaxMonede], P[NrMaxMonede];
unsigned n, S, Sum, NrSol;
ofstream fout("suma.out");
void Citire()
{//citesc datele de intrare din fisierul suma.in
ifstream fin("suma.in");
fin>>n>>S;
for (int i=0; i<n; i++) fin>>V[i]>>M[i];
fin.close();}
void Afisare()
{//afisez o solutie in fisierul de iesire
fout<< "Solutia nr. "<<++NrSol<<endl;
for (int i=0; i<n; i++)
if (P[i])
fout<<P[i]<<" monede cu valoarea "<<V[i]<<endl;}
void Plata(int k)
{/* cand apelam Plata(k) am selectat deja monede din
saculetii 0,1,...,k-1 */
if (k==n)
//am selectat monede de toate tipurile
if (Sum==S) //valoarea monedelor selectate e egala cu S
Afisare();
else;
else //mai selectam monede din saculetii k,k+1,...,n-1
for (int j=0; j<=M[k] && Sum+j*V[k]<=S; j++)
{P[k]=j;
//selectez j monede din saculetul k
Sum+=j*V[k];
/*adaug valoarea monedelor selectate din saculetul k
la valoarea totala a monedelor selectate memorata in Sum */
Plata(k+1);
//apel recursiv
Sum-=j * V[k];}
//restaurez dupa apel valoarea variabilei globale Sum
}
int main ()
{Citire();
Plata(0);
fout.close(); return 0;}

Observai c i n acest program am utilizat tehnica variabilei globale: pentru a


nu calcula la fiecare pas valoarea total a monedelor deja selectate, am reinut
aceast valoare n variabila global Sum. De fiecare dat cnd selectm monede
dintr-un scule, adugm valoarea lor la Sum, apoi apelm recursiv funcia Plata

74

3. METODA BATRACKING

care selecteaz n continuare monede din ceilali sculei pentru plata sumei. Cnd
revenim din apelul recursiv, trebuie s restaurm valoarea variabilei globale Sum
(deci trebuie s scdem din Sum valoarea monedelor selectate la pasul precedent
din sculeul k, pentru a putea aduga ulterior, dac este cazul, valoarea
corespunztoare monedelor selectate din sculeul k la pasul urmtor).
Observai de asemenea c am optimizat programul: dac la un moment dat
valoarea monedelor deja selectate depete suma S care trebuie pltit nu
continum generarea.

Generare ir
Se citesc de la tastatur numerele naturale n i lg (0<n, lg10). S se afieze
toate irurile de lg numere strict pozitive, iruri cu proprietatea c ncep i se
termin cu n, iar ntre dou elemente consecutive ale irului diferena este exact 1.
Dac nu exist nici o soluie, se va afia un mesaj. De exemplu, pentru n=2 i
lg=5, se vor afia soluiile (nu neaprat n aceast ordine):
2 3 4 3 2 ; 2 3 2 3 2 ; 2 3 2 1 2 ; 2 1 2 3 2 ; 2 1 2 1 2.
Simulare bacalaureat 2001

Soluie
Vom construi soluiile ntr-un vector s cu lg componente. n funcia main()
vom iniializa prima component a vectorului cu n (s[0]=n), pentru a ne asigura
c irul ncepe cu n.
Pentru a construi toate irurile care ncep cu n i respect proprietile din enun
vom utiliza o funcie recursiv Gen(). Cnd apelm funcia Gen(k), poziiile 0,
1, ..., k-1 din vectorul s sunt deja ocupate i trebuie s plasm elemente pe
poziiile k, k+1, ..., lg-1. Vom ocupa mai nti poziia k, apoi vom apela recursiv
funcia de generare pentru a construi irul n continuare (Gen(k+1)).
Pentru a ne asigura c diferena dintre oricare dou elemente consecutive din ir
este exact 1, pe poziia k pot fi plasate cel mult dou valori: s[k-1]-1 (doar dac
s[k-1]>1, pentru c n ir pot fi plasate valori strict pozitive) sau s[k-1]+1.
Atunci cnd vectorul s este complet, vom afia soluia obinut, testnd n
prealabil c pe ultima poziie n vector se afl valoarea n (s[lg-1]==n).
#include <fstream.h>
#define NMax 11
int s[NMax];
int n, lg;
long nrsol;
ofstream fout("sir.out");

75

3. METODA BACKTRACKING

void Afisare();
void Gen(int k)
//cand apelam Gen(k), am fixat in sir k valori
{ if (k==lg)
//sirul este complet
Afisare();
else
{if (s[k-1]>1)
{s[k]=s[k-1]-1;
Gen(k+1); }
s[k]=s[k-1]+1;
Gen(k+1);
}
}
int main()
{
cout<<"n, lg="; cin>>n>>lg;
s[0]=n;
Gen(1);
if (!nrsol) fout<<"Nu exista solutii\n";
fout.close();
return 0;
}
void Afisare()
{int i;
if (s[lg-1]==n)
{nrsol++;
for (i=0; i<lg; i++) fout<<s[i]<<' ';
fout<<endl; }
}

Observm c algoritmul precedent genereaz iruri care nu se termin


obligatoriu cu n, iar noi testm aceast condiie abia la final. Dac valoarea s[k]
va crete/scdea prea mult, nu mai exist anse ca pe ultima poziie n vector s
obinem valoarea n, oricum am genera valorile s[k+1], s[k+2], ..., s[lg-1].
Pentru a determina cea mai mic valoare care poate fi plasat pe poziia k,
presupunem c de la poziia k+1 pn la poziia lg-1 valorile vor fi n ordine
strict cresctoare.
Valoare minim
Poziie

?
...

...

n-2

n-1

lg-3

lg-2

lg-1

Observm c suma dintre valoarea minim i poziie este constant (n+lg-1).


Deducem astfel c cea mai mic valoare care poate fi plasat pe poziia k este nlg+1+k (cu condiia ca n-lg+1+k>0)

76

3. METODA BATRACKING

Pentru a determina cea mai mare valoare care poate fi plasat pe poziia k,
presupunem c de la poziia k+1 pn la poziia lg-1 valorile vor fi n ordine
strict descresctoare:
Valoare maxim
Poziie

?
...

...

n+2

n+1

lg-3

lg-2

lg-1

Observm c suma dintre valoarea maxim i poziie este constant (n+lg-1).


Deducem c valoarea maxim care poate fi plasat pe poziia k este n+lg-1-k.
Funcia de generare optimizat este:
void Gen(int k)
//cand apelam Gen(k), am fixat in sir k valori
{ if (k==lg)
//sirul este complet
Afisare();
else
{if (s[k-1]>1 && s[k-1]-1>=n-lg+1+k)
{s[k]=s[k-1]-1;
Gen(k+1); }
if (s[k-1]+1<=n+lg-1-k)
{s[k]=s[k-1]+1;
Gen(k+1);}
}
}

Exerciiu
Modificai programul precedent astfel nct s genereze toate irurile de
lungime lg, care ncep cu n i se termin cu n, diferena ntre oricare dou valori
consecutive fiind cel mult D.

Generare numere
Se citesc de la tastatur numerele naturale n i k (0<n10000 i 0<lg<10)
reprezentate n baza 10. S se afieze n ordine cresctoare toate numerele naturale
de lg cifre cu proprietatea c sunt formate numai cu cifre ale numrului n.
De exemplu, pentru n=216 i lg=2, se vor afia numerele: 11, 12, 16, 21,
22, 26, 61, 62, 66.
Bacalaureat special 2001
Soluie
n primul rnd vom construi vectorul caracteristic al mulimii cifrelor numrului
n. Soluiile vor fi generate n variabila x, de tip unsigned long (pentru c
numrul de cifre este < 10. Pentru a genera toate soluiile vom utiliza funcia
recursiv Gen(). Cnd apelm Gen(k) n numrul x au fost adugate k cifre;

3. METODA BACKTRACKING

77

adugm la sfritul numrului x, pe rnd, fiecare dintre cifrele numrului n, apoi


vom apelm recursiv Gen(k+1) pentru a completa numrul soluie.
#include <fstream.h>
int c[10];
int n, lg;
unsigned long x;
ofstream fout("sir.out");
void Determina_Cifre(int);
void Gen(int k)
//cand apelam Gen(k), am fixat in sir k valori
{int i;
if (k==lg)
//sirul este complet
fout<<x<<endl;
else
for (i=0; i<10; i++)
if (c[i])
//cifra i apare in n?
{x=x*10+i; //adaug la sfarsitul lui x cifra i
Gen(k+1); //generez in continuare
x/=10;
//sterg cifra adaugata
}
}
int main()
{
cout<<"n, lg="; cin>>n>>lg;
Determina_Cifre(n);
Gen(0);
fout.close();
return 0;
}
void Determina_Cifre(int x)
{
do
{c[x%10]=1;
x/=10; }
while (x);
}

Exerciiu
Modificai programul precedent astfel nct s genereze toate numerele formate
din lg cifre ale numrului n care au cifrele n ordine cresctoare. De exemplu,
pentru n=216 i lg=2, se vor afia numerele: 11, 12, 16, 22, 26, 66.

78

3. METODA BATRACKING

Comis-voiajor
Un comis voiajor plec din oraul n care locuiete (s-l notm 1) s prezinte
produsele unei firme n toate cele n orae din regiunea sa. El are la dispoziie harta
regiunii, pe care sunt marcate legturile directe dintre orae i distanele dintre
acestea. Scriei un program care s determine un traseu ct mai scurt, astfel nct
comisul voiajor s viziteze toate oraele din regiune, s nu treac de mai multe ori
prin acelai ora i s se ntoarc n oraul n care locuiete!
De exemplu, s presupunem c exist n=5 orae, numerotate de la 1 la 5. S
presupunem c harta regiunii indic urmtoarele legturi directe:
2
500
125
100
3
1
300
140
150
110
4
5
Pentru acest exemplu, programul va afia:
Traseul cel mai scurt are lungimea 815.00
Traseul este 1,3,4,2,5,1

Reprezentarea informaiilor
Vom reprezenta harta regiunii printr-o matrice ptratic A, cu nxn componente
avnd semnificaia: A[i][j]=0 dac ntre oraele i i j nu exist legtur
direct, respectiv distana dintre oraele i i j dac exist legtur direct.
Traseul, mai exact ordinea n care comisul voiajor viziteaz cele n orae, l vom
reine ntr-un vector T, cu n componente.
Pentru a nu trece de mai multe ori prin acelai ora, vom mai utiliza un vector v,
cu n componente, n care pentru fiecare ora vom reine dac a fost sau nu vizitat:
v[i]=1 dac oraul i a fost vizitat i 0 n caz contrar.
Cnd obinem un traseu soluie nu l afiam, ci l comparm cu traseul de
lungime minim obinut pn la momentul respectiv. Prin urmare, vom utiliza
TMin, un vector cu n componente, n care reinem un traseu de lungime minim i
o variabil global LgMin n care reinem lungimea acestui traseu.
Pentru a optimiza funcia de generare a traseelor, vom utiliza o variabil global
Lg n care reinem lungimea traseului curent. Astfel nu va mai fi nevoie s
calculm la fiecare pas lungimea traseului curent: cnd ne deplasm n alt ora
adunm distana pn la oraul respectiv la Lg. Cnd eliminm un ora de pe
traseu, scdem distana pn la acesta din Lg. Dac la un moment dat Lg>LgMin,

3. METODA BACKTRACKING

79

nu mai continum generarea acestui traseu, deoarece lungimea lui a depit deja
lungimea celui mai scurt traseu obinut pn la momentul respectiv.
Condiii interne
1. T[i]{1,2,,n} i{1,2,,n}
(traseul conine cele n orae)
2. T[1]=1
(comis voiajorul pleac din oraul 1)
3. A[T[i]][T[i+1]]=1 i{1,2,,n-1}
(ntre dou orae vizitate succesiv trebuie s existe legtur direct)
4. T[i]T[j] ij, i,j{1,2,,n}
(comisul voiajor nu trece de mai multe ori prin acelai ora)
5. A[1][T[n]]=1
(trebuie s existe legtur direct ntre oraul de plecare i ultimul ora vizitat).
#include <iomanip.h>
#include <fstream.h>
#define NMaxOrase 20
float A[NMaxOrase][NMaxOrase];
int n;
int T[NMaxOrase], TMin[NMaxOrase], v[NMaxOrase];
float Lg, LgMin, Inf;
void Citire()
{ifstream f("comis.in");
int i, j;
float d;
f>>n;
while (!f.eof())
/* de pe fiecare linie citesc doua orase intre care exista
legatura directa, precum si distanta dintre ele */
{f>>i>>j>>d;
A[i][j]=A[j][i]=d; }
f.close(); }
float Infinit()
//intoarce un numar suficient de mare
{float s=0;
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++) s+=A[i][j];
return s+1; }
void Afisare()
{ if (LgMin==Inf) cout<<"Nu exista solutii\n";
else
{cout<<"Traseul cel mai scurt are lungimea ";
cout<< setprecision(10) << LgMin << endl;
cout<<"Traseul este ";
for (int i=1; i<=n; i++) cout<<TMin[i]<<',';
cout<<TMin[1]<<endl; }
}

80

3. METODA BATRACKING

void ConstrTraseu(int k)
/*cand apelam ConstrTraseu(k) sunt fixate pe traseu orasele
T[1], T[2], ..., T[k-1] */
{ if (k-1==n)
//traseul este complet
if (A[1][T[n]])
//poate reveni in orasul 1
if (Lg+A[1][T[n]]<LgMin)
{
//am obtinut un traseu mai scurt
for (int i=1; i<=n; i++) TMin[i]=T[i];
LgMin=Lg+A[1][T[n]]; }
else;
else;
else
//construiesc in continuare traseul
for (int i=2; i<=n; i++)
//verific daca se poate deplasa in orasul i
if (A[i][T[k-1]] && !v[i])
{T[k]=i; v[i]=1; Lg+=A[i][T[k-1]];
if (Lg<=LgMin) ConstrTraseu(k+1);
v[i]=0; Lg-=A[i][T[k-1]];}
}
int main()
{ Citire();
T[1]=v[1]=1; LgMin=Inf=Infinit();
ConstrTraseu(2);
Afisare();
return 0;
}

Medii
Se tie c media la o materie unde se d tez se calculeaz dup formula
urmtoare, unde Nt reprezint nota la tez, iar Mn media notelor la oral. Se tie, de
asemenea, c un elev poate avea la oral minim 3 i maxim 10 note.

media

Nt 3 * Mn
4

Cerin
n aceste condiii, dac doi elevi au aceeai medie i aceeai not la tez s se
determine toate combinaiile distincte de note pe care le pot avea cei doi elevi.
Date de intrare
Fiierul de intrare medii.in conine pe prima linie, separate printr-un spaiu,
media i nota la tez.

81

3. METODA BACKTRACKING

Date de ieire
Dac exist soluie, fiierul de ieire medii.out conine pe fiecare linie cte o
combinaie de note, notele fiind separate prin cte un spaiu. Dac nu exist soluie,
n fiierul de ieire se va scrie mesajul NU.
Restricii
1 Nt 10
1 media 10
Media se d n fiierul de intrare cu 3 zecimale exacte.
Exemplu
medii.in

medii.out

Comentarii

5.625 3

...
2 3 4 7 7 9 10 10
...
5 6 6 9
...

Exist mai multe combinaii de note


care furnizeaz aceeai medie, dou
dintre acestea fiind cele indicate.
Mn=(5+6+6+9)/4=26/4=6.50
Media_calculat=(3+3*6.50)/4=
22.50/4 = 5.625
Olimpiada municipal de Informatic, Iai 2003

Soluie
Avnd n vedere c se cer toate combinaiile de note care furnizeaz aceeai medie,
rezult c problema se rezolv prin tehnica de programare backtracking.
Reprezentarea informaiilor
Notele la oral care particip la calcularea mediei se rein n ordine cresctoare
ntr-un tablou n. Deoarece cea mai mic not este nota 1, i notele se rein n
ordine cresctoare, vom iniializa prima valoare a acestui tablou (n[0]) cu 1,
urmnd ca notele care particip efectiv la calcularea mediei s fie reinute n
continuare (n[1], ..., n[10]).
Condiii interne
1. n[i]{1, ..., 10}, i{1, ..., 10}
2. n[0]=1
3. n[i]n[i+1], i{0, ..., 9}
Se genereaz n vectorul n toate combinaiile de minim trei i maxim zece note.
Dup fiecare not adugat se calculeaz media i, n cazul n care aceasta coincide
cu media dat, se afieaz soluia.

82

3. METODA BATRACKING

#include <stdio.h>
FILE *f, *g;
float media, nt;
int n[12], GASIT;
void afiseaza(int k)
{ int i;
for (i=1; i<=k; i++)
fprintf(g, "%d ", n[i]);
fprintf(g, "\n");
GASIT=1;
//am gasit solutie
}
float media_calculata(int k)
{ int i;
float s, mn, mc;
if (k>2) //are rost sa calculez doar daca am minim 3 note
{ s=0;
for (i=1; i<=k; i++) s+=n[i]; //suma notelor
mn=s/k;
//media notelor
mc=(nt+3.0*mn)/4.0;
//media calculata
return mc;
}
return 0;
}
void calculeaza(int k)
{ int i;
if (k<11) //daca nu am pus toate notele (maxim 10 aici)
{
for (i=n[k-1]; i<=10; i++)//pun toate notele posibile
{
n[k]=i;
//pun nota i
if (media_calculata(k)==media)
//daca media corespunde
afiseaza(k);
//afiseaza
calculeaza(k+1);
//treci la nota urmatoare
n[k]=0;
//anuleaza ultima nota
}
}
}
int main()
{ f=fopen("medii.in", "r");
g=fopen("medii.out", "w+");
fscanf(f, "%f %f", &media, &nt);
GASIT=0;
//nu am gasit nici o solutie
n[0]=1;
//ca sa plec de la nota 1

3. METODA BACKTRACKING

83

calculeaza(1);
//pune notele incepand cu prima
if (!GASIT) fprintf(g, "NU\n");
fclose(f); fclose(g);
return 0;
}

Domino
S se afieze cel mai lung lan ce se poate construi din cele n piese ale unui joc
de domino, tiind c fiecare pies are nscrise n ordine dou numere din mulimea
{1,2,3,4,5,6}, iar dou piese se pot plasa pe lan n poziii consecutive dac
i numai dac primul numr nscris pe cea de a doua pies coincide cu cel de al
doilea numr nscris pe prima pies.
De exemplu, pentru n=6 piese, care au nscrise numerele 4 2, 1 2, 4 4,
1 3, 2 5, 6 5 programul va afia:
Cel mai lung lant este format din piesele 3 1 2 4

Reprezentarea informaiilor
Vom reprezenta un joc de domino reinnd ntr-un vector J valorile nscrise pe
fiecare pies din joc.
O soluie va fi reprezentat ntr-un vector L, n care reinem n ordine indicii
pieselor din joc ce formeaz un lan.
Soluia optim (cel mai lung lan care se poate construi cu piese din joc) o vom
reine ntr-un vector LMax, n care vom memora, n ordine, indicii pieselor care
constituie un cel mai lung lan. Cnd obinem n L o soluie maximal (care nu mai
poate fi mrit, un lan la care nu mai putem lipi nici o pies) o vom compara cu
lanul cel mai lung obinut pn la momentul respectiv i, dac lanul din L este
mai lung l vom reine n LMax.
Deoarece n lan nu putem utiliza o aceeai pies de mai multe ori, vom utiliza
un vector Uz, cu n componente (Uz[i]=1 dac piesa cu indicele i a fost folosit
n lanul L i 0, n caz contrar).
Condiii interne
1. L[i]{1,2,,n} i{1,2,,n}
(lanul este format din indici ai pieselor din joc);
2. L[i]L[j] ij, i,j{1,2,,n}
(nu se poate folosi o pies de mai multe ori);
3. J[L[i]].ultim = J[L[i+1]].prim, i{1,2,,n-1}
(pentru oricare dou piese consecutive pe lan, a doua valoare nscris pe prima
dintre piese coincide cu cea de a doua valoare nscris pe piesa urmtoare).

84

3. METODA BATRACKING

#include <fstream.h>
#define NrMaxDomino 100
struct Piesa { int prim, ultim; } J[NrMaxDomino];
//pentru fiecare piesa retin cele doua numere inscrise
int n, LgMax;
int L[NrMaxDomino], LMax[NrMaxDomino], Uz[NrMaxDomino];
void Citire()
{ifstream fin("domino.in");
fin>>n;
for (int i=1; i<=n; i++) fin>>J[i].prim>>J[i].ultim;
fin.close(); }
void Afisare()
{cout<<"Cel mai lung lant este format din piesele ";
for (int i=1; i<=LgMax; i++)
cout<<LMax[i]<<' ';}
void ConstrLant(int k)
//lantul contine k-1 piese de domino
{int Se_Poate=0;
//incerc sa prelungesc lantul
for (int i=1; i<=n; i++)
if (!Uz[i])
//nu am mai utilizat piesa i
{if (J[i].ultim == J[L[k-1]].ultim)
{
//intoarce piesa
int aux=J[i].prim;
J[i].prim=J[i].ultim; J[i].ultim=aux;}
if (J[i].prim == J[L[k-1]].ultim)
{
//piesa i "se lipeste"
L[k]=i; Uz[i]=1; Se_Poate=1;
ConstrLant(k+1);
Uz[i]=0;}
}
if (!Se_Poate)
//am obtinut o solutie maximala
if (k-1 > LgMax)
//compar lantul curent cu cel maxim
{LgMax=k-1;
for (i=1; i<=LgMax; i++) LMax[i]=L[i];}
}
int main()
{ Citire();
for (int i=1; i<=n; i++)
{
//pot incepe lantul cu orice piesa
L[1]=i; Uz[i]=1;
ConstrLant(2);
Uz[i]=0;}
Afisare();
return 0; }

3. METODA BACKTRACKING

85

Scara
Ion i-a construit o vil pe frumosul vrf al unui munte. Acum proiecteaz o
scar special, pe care va urca de la osea pn la vil. Diferena de nivel dintre
osea i vil este H (deci aceasta trebuie s fie nlimea total a scrii). Scara va
avea N trepte, toate de aceeai lime, dar de nlimi distincte dou cte dou.
Ion a sesizat c efortul pe care l depune pentru a urca o treapt este egal cu
nlimea treptei. Dar dac el urc x trepte deodat, efortul depus este egal cu
media aritmetic a nlimilor acestor x trepte pe care le urc deodat + un efort de
valoare constant p (necesar pentru a-i lua avnt).
Fiind un tip atletic, Ion poate urca mai multe trepte deodat, dar suma
nlimilor treptelor urcate deodat nu trebuie s depeasc o valoare maxim M.
Cerin
Scriei un program care s determine efortul minim necesar pentru a urca pe o
scar construit conform restriciilor problemei, precum i o modalitate de a
construi scara care va fi urcat cu efort minim.
Date de intrare
Fiierul de intrare scara.in va conine pe prima linie 4 numere naturale
separate prin cte un spaiu H N M p (cu semnificaia din enun).
Date de ieire
Fiierul de ieire scara.out va conine
pe prima linie va fi scris efortul minim necesar (cu 2 zecimale cu rotunjire);
pe cea de a doua linie vor fi scrise N numere naturale nenule care reprezint
nlimile celor N trepte ale scrii (n ordinea de la osea ctre vil), separate
prin cte un spaiu.
Restricii i precizri
0 < H 75
0 < N 8
0 < M < 14
0 p 10
Pentru datele de test, problema are ntotdeauna soluie.
Dac exist mai multe soluii (modaliti de a construi scara astfel nct s
obinei efortul minim dorit), vei afia prima soluie n ordine lexicografic.
Spunem c vectorul x=(x1, x2, ..., xk) preced n ordine lexicografic vectorul
y=(y1, y2, ..., yk) dac exist i1 astfel nct xj=yj, pentru orice j<i i
xi<yi.

86

3. METODA BATRACKING

Dac a doua zecimal a efortului minim este 0, sau chiar ambele zecimale sunt
0 nu este necesar s le afiai. Deci n exemplu s-ar fi putut scrie efortul minim
9 sau 9.0.
Exemplu
scara.in
10 4 5 2

scara.out
9.00
1 4 2 3
Olimpiada Judeean de Informatic, 2005

Soluie
Reprezentarea informaiilor
1. Vectorul n care generm soluiile: sol, cu n componente, cu semnificaia
sol[i]=nlimea treptei i
2. Soluia care necesit efort minim o vom reine n vectorul solmin
3. Pentru a verifica dac toate nlimile sunt distincte vom construi vectorul uz cu
M componente, vectorul caracteristic al nlimilor (nu putem folosi nlimi mai
mari dect M):
uz[i]=1, dac nlimea i a fost utilizat i 0 n caz contrar
4. htot=suma nlimilor treptelor pn la un moment dat
5. efmin=efortul consumat pentru solmin
6. Pentru a calcula efortul minim necesar la fiecare pas, vom utiliza un vector ef
cu n componente, cu semnificaia:
ef[i]=efortul minim necesar pentru a urca primele i trepte din soluia
memorat n vectorul sol
Condiii interne
1. sol[i] {1, 2, ..., M}, i{1, 2, ..., N}
2. sol[i] sol[j], ij i, j{1, 2, ..., N}
3. sol[1]+s[2]+...+sol[N]=H
Treptele 1, 2, ..., i se pot urca cu efort minim astfel:
urcm cu efort minim treptele 1, 2, ..., i-1 i apoi urcm separat treapta i
(efortul necesar n acest caz este ef[i-1]+sol[i]);
urcm cu efort minim treptele 1, 2, ..., j, apoi urcm deodat treptele j+1,
j+2, ..., i, dac este posibil, adic dac suma nlimilor acestor trepte nu
depete M (sol[j+1]+sol[j+2]+...+sol[i])M); efortul depus
este ef[j]+p+(sol[j+1]+sol[j+2]+...+sol[i])/(i-j). Treapta

3. METODA BACKTRACKING

87

j poate fi aleas n toate modurile posibile (j=i-2, i-3, ...), varianta


convenabil fiind cea care minimizeaz efortul depus.
Deducem din acest raionament c efortul minim necesar pentru a urca treptele
1, 2, ..., i se calculeaz astfel:
ef[i]=min {ef[i-1]+sol[i],
min {ef[j]+p+(sol[j+1]+sol[j+2]+...+sol[i])/(i-j),
j=i-2,i-3...
dac (sol[j+1]+sol[j+2]+...+sol[i])M}

#include <fstream.h>
#include <iomanip.h>
#define InFile "scara.in"
#define OutFile "scara.out"
#define NMax 101
#define HMax 101
int sol[NMax], solmin[NMax], uz[HMax], htot;
double ef[NMax], efmin;
//ef[i]=efortul minim cu care urc primele i trepte din sol
int N, H, p, M;
void Citire();
void Gen(int);
void Afisare();
double efort ();
int main()
{Citire();
efmin=(double)H*N+1;
Gen(1);
Afisare();
return 0;
}
void Citire()
{ifstream fin(InFile);
fin>>H>>N>>M>>p;
fin.close();
}
void Afisare()
{int i;
ofstream fout(OutFile);
fout<<setprecision(2)<<efmin<<endl;
for (i=1; i<N; i++)
fout<<solmin[i]<<' ';
fout<<solmin[N]<<endl;
fout.close();
}

88

3. METODA BATRACKING

double efort()
{int k, j;
double x, sum;
for (k=1; k<=N; k++)
{x=sol[k]+ef[k-1];
/* urc cu efort minim primele k-1 trepte si apoi urc
treapta k de inaltime i */
sum=sol[k];
for (j=2; k-j>=0; j++)
{/* urc deodata j trepte k, k-1, ..., k-j+1, daca
suma inaltimilor lor este <=M;
in sum calculez suma inaltimilor */
sum+=sol[k-j+1];
if (sum>M) break;
if (sum/j+p+ef[k-j]<x)
x=sum/j+ef[k-j]+p;
}
ef[k]=x;
}
return ef[N];
}
void Gen(int k)
{
int i;
double x;
if (k==N+1)
{
if (htot==H)
{x=efort();
if (x<efmin && efmin-x>0.001)
{efmin=x;
for (i=1; i<=N; i++) solmin[i]=sol[i]; }
}
}
else
for (i=1; i<=H && htot+i<=H && i<=M; i++)
if (!uz[i])
{
/* care ar fi efortul minim daca as pune
inaltimea treptei k=i? */
sol[k]=i; htot+=i; uz[i]=1;
Gen(k+1);
uz[i]=0; htot-=i;
}
}

89

3. METODA BACKTRACKING

Staie
n laboratoarele unei staii spaiale exist un simulator centrifugal care conine C
camere, numerotate de la 1 la C. ntr-o camer pot s ncap 0, 1 sau 2 persoane.
Coeficientul de dezechilibrare a unui simulator se calculeaz astfel:
C
Cdez = |MCi - MA|
i=1
unde MCi este masa camerei i (calculat prin nsumarea maselor persoanelor din
camera respectiv), iar MA este masa medie a camerelor (calculat prin nsumarea
maselor tuturor persoanelor din camere, i mprirea sumei la numrul de camere).
La un experiment de simulare particip S persoane, numerotate de la 1 la S.
Cerin
Scriei un program care s determine coeficientul de dezechilibrare minim ce se
poate obine prin repartizarea celor S persoane n camerele simulatorului.
Date de intrare
Fiierul de intrare statie.in conine:
Semnificaie

statie.in
C S
M1 M2 ... MS

C numrul de camere dintr-un simulator


S numrul de persoane
Mi masa persoanei i

Date de ieire
Fiierul de ieire statie.out va conine
statie.out
Cdez

Semnificaie
Cdez reprezint coeficientul de dezechilibrare minim
al simulatorului

Restricii
1 C 5
1 S 2C
1 Mi 1000, i=1, 2, ..., S
Coeficientul de dezechilibrare Cdez va fi afiat cu 3 zecimale.
Exemplul 1

statie.in
2 3
6 3 8

statie.out
1.000

Explicaie
O soluie este: persoanele 1 i 2 sunt plasate n camera 1;
persoana 3 este plasat n camera 2.

90

3. METODA BATRACKING

Coeficientul de dezechilibrare este 1.000

Exemplul 2
statie.in
5 9
1 2 3 5 7 11 13 17 19

statie.out
11.600

Explicaie
O soluie este: persoanele 1 i 8 sunt
plasate n camera 1; persoanele 2 i 7
sunt plasate n camera 2; persoanele 3 i
6 sunt plasate n camera 3; persoanele 4
i 5 sunt plasate n camera 4; persoana 9
este plasat n camera 5.
Coeficientul de dezechilibrare este
11.600

.campion, 2004

Soluie
Deoarece se cere determinarea unei repartizri optime a celor S persoane n
camere i deoarece dimensiunile datelor nu sunt mari, vom aplica o metod de tip
backtracking, ncercnd s repartizm persoanele n camerele care mai au locuri
disponibile. O camer este caracterizat de numrul de persoane repartizate la un
moment dat n camer i greutile persoanelor respective. n momentul n care
toate cele S persoane au fost repartizate n camere se calculeaz coeficientul de
dezechilibrare a staiei i, n cazul n care a fost determinat un coeficient mai bun, l
reinem.
#include <stdio.h>
#define Infinit 99999
typedef struct
{
long nr,
pers[2];
} camera;
long
camera
int
long

//structura unei camere


//numarul de persoane
//cele (maxim) 2 persoane (greutatile)

pers[10];
cam[5], best_cam[5];
nr_cam, nr_pers;
best_Cdez=Infinit, medie;

long abs(long x)
{ if (x<0) return -x;
return x; }
long calc_Cdez(void) //calculeaza coef de dezechilibru
{long Cdez=0;
int i,j;
for (i=0; i<nr_cam; i++)
Cdez+=abs((nr_cam*(cam[i].pers[0]+cam[i].pers[1]))-medie);
return(Cdez);

3. METODA BACKTRACKING

91

}
void citire(void)
{ int i;
FILE *inp=fopen("statie.in","r");
fscanf(inp, "%d %d", &nr_cam, &nr_pers);
medie = 0;
for (i=0; i<5; i++) //initializeaza cu 0 toate camerele
{ cam[i].nr=0;
//numarul de persoane
cam[i].pers[0]=0;
//persoana 1
cam[i].pers[1]=0;
//persoana 2
}
for (i=0; i<nr_pers; i++) //greutatile persoanelor
{fscanf(inp, "%d ", &(pers[i]));
medie+=pers[i]; //se calculeaza si suma greutatilor
}
fclose(inp); }
void calcul(int k)
{ long temp;
int i,j;
if (k==nr_pers)
//daca le-am repartizat pe toate
{
temp=calc_Cdez();
//calculam coef de dezechilibru
if (temp<best_Cdez) //daca e mai bun
best_Cdez=temp;
//il retinem
}
else
//nu i-am repartizat pe toti
for (j=0; j<nr_cam; j++)//parcurg toate camerele si
if (cam[j].nr<2)
//daca in camera j mai e loc
{
cam[j].pers[cam[j].nr]=pers[k];//pun pers k aici
cam[j].nr++;
//numar inca o persoana
calcul(k+1);
//trec la persoana urmatoare
cam[j].nr--;
//revin scad numarul de persoane
cam[j].pers[cam[j].nr]=0;//greutatea la loc pe 0
}
}
void afisare(void)
{FILE *g;
g=fopen("statie.out","w");
fprintf(g,"%5.3f\n",((float)(best_Cdez))/((float)nr_cam));
fclose(g); }
int main(void)
{ citire();
calcul(0);
afisare();

92

3. METODA BATRACKING

return 0; }

3.4. Bactracking n plan


n variant elementar aplicam metoda backtracking pentru rezolvarea
problemelor n care soluia era reprezentat ca vector. Putem generaliza ideea
cutrii cu revenire i pentru probleme n care cutarea se face n plan. Pentru
noi planul va fi reprezentat ca un tablou bidimensional.
Pentru a intui modul de funcionare a metodei backtracking n plan s ne
imaginm explorarea unei peteri. Speologul pornete de la intrarea n peter i
trebuie s exploreze n mod sistematic toate culoarele peterii. Ce nseamn n
mod sistematic? n primul rnd i stabilete o ordine pentru toate direciile
posibile de micare (de exemplu, N, NE, E, SE, S, SV, V, NV) i ntotdeauna cnd
se gsete ntr-un punct din care are mai multe culoare de explorat, alege direciile
de deplasare n ordinea prestabilit. n al doilea rnd, speologul va plasa marcaje
pe culoarele pe care le-a explorat, pentru ca nu cumva s se rtceasc i s
parcurg de mai multe ori acelai culoar (ceea ce ar conduce la determinarea
eronat a lungimii peterii).
n ce const explorarea? Speologul exploreaz un culoar pn cnd ntlnete o
intersecie sau pn cnd culoarul se nfund. Dac a ajuns la o intersecie,
exploreaz succesiv toate culoarele care pornesc din intersecia respectiv, n
ordinea prestabilit a direciilor. Cnd un culoar se nfund, revine la intersecia
precedent i alege un alt culoar, de pe urmtoarea direcie (dac exist; dac nu
exist, revine la intersecia precedent .a.m.d.).
S descriem ntr-o form mai general aceast metod.
Vom nota prin NrDirectii o constant care reprezint numrul de direcii de
deplasare, iar dx, respectiv dy sunt doi vectori constani care reprezint deplasrile
relative pe direcia Ox, respectiv pe direcia Oy, urmnd n ordine cele
NrDirectii de deplasare.
void Bkt_Plan(int x, int y)
//x, y reprezinta coordonatele pozitiei curente
{
Explorare(x,y);
//exploram pozitia curenta
if (EFinal(x,y))
//pozitia x,y este un punct final
Prelucrare_Solutie();
else
//continuam cautarea
for (i=0; i<NrDirectii; i++)
//ma deplasez succesiv pe directiile posibile de miscare
if (Nevizitat(x+dx[i], y+dy[i]))
//nu am mai trecut prin aceasta pozitie
Bkt_Plan(x+dx[i], y+dy[i]);
}

93

3. METODA BACKTRACKING

Labirint
ntr-un labirint, reprezentat ca o matrice L, cu n linii i m coloane, cu
componente 0 sau 1, (1 semnificnd perete, 0 culoar) se gsete o bucat de
brnz pe poziia (xb, yb) i un oricel pe poziia (xs, ys). Afiai toate
posibilitile oricelului de a ajunge la brnz, tiind c el se poate deplasa numai
pe culoar, iar direciile posibile de micare sunt N, NE, E, SE, S, SV, V, NV.
De exemplu, pentru un labirint cu 4 linii i 4 coloane de forma urmtoare, n
care oricelul se gsete pe poziia 1 1, iar brnza pe poziia 4 4
0
0
0
1

1
1
1
0

1
1
0
1

1
1
0
0

programul va afia:
Solutia nr. 1
*111
*111
*1**
1*1*
Solutia nr. 2
*111
*111
*1*0
1*1*

Reprezentarea informaiilor
Labirintul este reprezentat ca o matrice L, cu nxm elemente. Elementele
labirintului sunt iniial 0 (semnificnd culoar) i 1 (semnificnd perete). Pentru ca
oricelul s nu treac de mai multe ori prin aceeai poziie, existnd riscul de a intra
n bucl, vom marca n labirint poziiile prin care trece oricelul cu 2.
Pentru a determina poziiile n care se poate deplasa oricelul, vom utiliza doi
vectori Dx[8] i Dy[8], pe care i iniializm cu deplasrile pe linie, respectiv pe
coloan pentru toate cele 8 direcii posibile de micare.
NV

NE

L[x-1][y-1]

L[x-1][y]

L[x-1][y+1]

L[x][y-1]

L[x][y]

L[x][y+1]

SV

SE

L[x+1][y-1]

L[x+1][y]

L[x+1][y+1]

94

3. METODA BATRACKING

Pentru a nu verifica permanent dac oricelul nu a ajuns cumva la marginea


labirintului, bordm labirintul cu perete ( dou linii i dou coloane cu valoarea 1).
Condiii interne
Din poziia (x,y) oricelul se poate deplasa pe direcia dir, deci n poziia
(x+Dx[dir], y+Dy[dir]) dac i numai dac
L[x+Dx[dir]][y+Dx[dir]]=0
(aceast poziie reprezint un culoar prin care oricelul nu a mai trecut).
#include <fstream.h>
#define DimMax 20
int Dx[8]={-1,-1,0,1,1,1,0,-1};
int Dy[8]={0,1, 1,1,0,-1,-1,-1};
int L[DimMax][DimMax];
int n, m, xs, ys, xb, yb, NrSol;
ofstream fout("labirint.out");
void Citire()
{ifstream f("labirint.in");
f>>n>>m>>xs>>ys>>xb>>yb;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++) f>>L[i][j];
f.close();}
void Bordare()
{
//bordam labirintul cu cate un perete
for (int i=0; i<=n+1; i++)//perete la stanga si la dreapta
L[i][0]=L[i][m+1]=1;
for (i=0; i<=m+1; i++)
//perete sus si jos
L[0][i]=L[n+1][i]=1; }
void Afisare()
{fout<<"Solutia nr. "<<++NrSol<<endl;
for (int i=1; i<=n; i++)
{for (int j=1; j<=m; j++)
if (L[i][j] == 2) fout<<'*';
else fout<<L[i][j];
fout<<endl;}
}
void Cauta(int x, int y)
{ L[x][y]=2;
//marchez pozitia x y
if (x == xb && y == yb) Afisare();
else
for (int dir=0; dir<8; dir++)
if (!L[x+Dx[dir]][y+Dy[dir]]) //culoar nevizitat
Cauta(x+Dx[dir], y+Dy[dir]);
L[x][y]=0;
/*la intoarcere sterg marcajul, pentru a putea explora
acest culoar si in alta varianta*/
}

3. METODA BACKTRACKING

95

int main()
{ Citire(); Bordare();
Cauta(xs, ys);
if (!NrSol) fout<<"Nu exista solutii!\n";
fout.close();
return 0;
}

Exerciiu
Executai programul pas cu pas i urmrii valorile variabilelor globale i locale.

Fotografie
Fotografia alb-negru a unui obiect este reprezentat sub forma unei matrice cu n
linii i m coloane ale crei elemente sunt 0 sau 1. Elementele egale cu 1 reprezint
punctele ce aparin unui obiect. Dou elemente de valoare 1 fac parte din acelai
obiect dac sunt adiacente pe linie sau pe coloan. Se cere s se determine numrul
obiectelor din fotografie.
De exemplu, pentru matricea:
3
1
0
0

6
0 0 0 0 0
1 0 0 1 1
1 0 0 1 0

programul va afia:
Nr. obiecte = 3

Soluie
Pentru a numra obiectele din fotografie, vom parcurge matricea care reprezint
fotografia, cutnd un element cu valoarea 1, deci care aparine unui obiect. Vom
numra noul obiect depistat, apoi vom terge obiectul din fotografie, colorndu-l
n culoarea de fond (valoarea 0 n matrice). Pentru a terge un obiect vom folosi
funcia recursiv Sterge_Obiect(x, y), care n cazul n care punctul de
coordonate (x,y) aparine obiectului (a[x][y]=1), l terge (a[x][y]=0),
apoi se apeleaz recursiv funcia pentru toate punctele adiacente cu (x,y) (pe
linie sau pe coloan).
Pentru a nu testa dac n timpul cutrii am depit marginile fotografiei, am
bordat matricea care reprezint fotografia cu cte o linie i o coloan sus, jos,
stnga, dreapta iniializate cu valoarea 0 (am nrmat fotografia).
Observaie
Acest tip de algoritm, prin care plecnd de la un element sunt atinse succesiv
toate elementele care au o legtur (direct sau indirect) cu elementul respectiv
poart numele de algoritm de fill (umplere).

96

3. METODA BATRACKING

#include <fstream.h>
#define DimMax 50
int Dx[4]={-1, 0, 1, 0}, Dy[4]={ 0, 1, 0,-1};
int a[DimMax][DimMax], m, n, NrObiecte;
void Citire()
{ifstream fin("foto.in");
fin>>n>>m;
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++) fin>>a[i][j];
fin.close();}
void Sterge_Obiect(int x , int y)
{ if (a[x][y])
{ a[x][y]=0;
//sterg acest element de imagine
//cautarea continua in cele 4 directii posibile
for (int dir=0; dir<4; dir++)
Sterge_Obiect(x+Dx[dir], y+Dy[dir]);}
}
int main()
{ Citire();
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
if (a[i][j])
//am depistat un obiect
{NrObiecte++;
Sterge_Obiect(i, j);}
cout<<"Nr. obiecte = "<<NrObiecte<<endl;
return 0;}

Cel mai lung prefix


Fie C, o matrice cu n linii i m coloane, care conine numai litere. S se
determine cel mai lung prefix al unui cuvnt dat s, care s se gseasc n matricea
C, astfel nct oricare dou litere succesive ale prefixului s se afle n matrice pe
poziii adiacente (pe linie, coloan sau diagonal). Nu se va face distincie ntre
literele mari i cele mici.
De exemplu, pentru cuvntul s='elefantel' i matricea:
elean
ghanr
ttnde
elfen
aeatt

prefixul maximal obinut va fi: elefa.

3. METODA BACKTRACKING

97

Soluie
Vom utiliza funcia recursiv Cauta(x,y), care verific dac urmtoarea
liter din cuvnt (indicat de variabila global Lg, care reine lungimea prefixului
curent) se afl sau nu pe poziia (x,y) n matricea C. n caz afirmativ, am mai
gsit o liter n matrice, deci lungimea prefixului curent crete i continum
cutarea n poziiile adiacente poziiei (x,y). Altfel am obinut un prefix maximal
i comparm lungimea lui cu lungimea celui mai lung prefix determinat pn la
momentul curent (LgMax).
Pentru a nu verifica permanent dac prin deplasri succesive nu am depit
lungimea cuvntului sau limitele indicilor din matrice, vom borda matricea cu
spaii i vom marca sfritul cuvntului prin caracterul '.'.
De data aceasta nu trebuie s marcm literele din matrice pe care le-am utilizat
pentru construirea prefixului din dou motive:
putem utiliza aceeai liter de mai multe ori;
nu exist riscul de a apela recursiv funcia Cauta la infinit (sau mai exact
pn se umple stiva) deoarece la fiecare apel mrim Lg, lungimea prefixului
curent, i dup strlen(s) pai vom ajunge la '.', marcajul de sfrit de
cuvnt.
#include <fstream.h>
#include <ctype.h>
#include <string.h>
#define DimMax 30
//dimensiunea maxima a labirintului
int Dx[8]={-1,-1,0,1,1,1,0,-1};
int Dy[8]={0,1, 1,1,0,-1,-1,-1};
char s[200];
int Lg, LgMax, n, m;
char C[DimMax][DimMax];
void Citire()
{ifstream fin("prefix.in");
fin.getline(s, sizeof(s)); fin>>n>>m; fin.get();
for (int i=1; i<=n; i++)
{for (int j=1; j<=m; j++)
fin.get(C[i][j]);
fin.get();}
fin.close();}
void Bordare()
{//bordez matricea cu spatii
for (int i=0; i<=n+1; i++) C[i][0]=C[i][m+1]=' ';
for (i=0; i<=m+1; i++)
C[0][i]=C[0][n+1]=' '; }

98

3. METODA BATRACKING

void Cauta(int i, int j)


{/*verific daca elementul de pe linia i coloana j coincide
cu litera de pe pozitia Lg din cuvant */
if (tolower(C[i][j])==tolower(s[Lg])) //am gasit o litera
{ Lg++;
//lungimea prefixului curent creste
for (int k=0; k<8; k++) Cauta(i+Dx[k], j+Dy[k]);
Lg--; }
//restaurez lungimea prefixului curent
else
//prefixul este maximal
if (Lg>LgMax) LgMax=Lg;
/*am comparat lungimea prefixului curent cu lungimea
maxima obtinuta pana acum si, daca este cazul, o retin*/
}
int main()
{ Bordare(); Citire();
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++) Cauta(i,j);
s[LgMax]=NULL;
cout<<"Prefixul maximal este " << s;
return 0;}

Albina
Pe un gazon de form dreptunghiular au fost plantate pe fiecare din cele n
rnduri cte m fire de flori de diferite specii. O albin, ncntat de coloritul i de
mireasma florilor, va ncerca s polenizeze ct mai multe dintre acestea. Albina se
afl iniial n a k-a floare din rndul r i la fiecare pas poate zbura din floarea n
care se afl n una dintre cele patru flori vecine acesteia situate pe cele patru
direcii N, E, S, V. Diversitatea tipurilor de flori face ca inflorescenele acestora s
se afle la diferite nlimi fa de sol, fapt ce va ngreuna zborul albinei. Din acest
motiv, pentru a-i conserva energia, albina va putea zbura la fiecare pas cel mult
h1 uniti n sus sau cel mult h2 uniti n jos.
Cerin
Cunoscnd nlimea fiecrui fir de floare, determinai aria celei mai mari
suprafee dreptunghiulare cu flori polenizate de albin.
Date de intrare
Fiierul de intrare albina.in va conine:
pe prima linie numerele n i m separate printr-un spaiu, reprezentnd
dimensiunile gazonului;
pe linia a doua numerele k i r separate printr-un spaiu, reprezentnd poziia
iniial a albinei ;
pe cea de-a treia linie numerele h1 i h2, separate printr-un spaiu,
reprezentnd diferenele de nivel pe care le poate aborda albina ;

99

3. METODA BACKTRACKING

pe fiecare dintre urmtoarele n linii, cte m numere naturale separate prin spaii,
reprezentnd nlimile florilor
Date de ieire
Fiierul de ieire albina.out va conine pe prima linie un singur numr
natural, reprezentnd aria celei mai mari suprafee cu flori polenizate de albin.
Restricii i precizri
1 n, m 30
1 h1, h2 20
nlimea fiecrui fir de floare este un numr natural din intervalul [1,100].
Exemplu
albina.in
4
1
2
1
4
3
1

4
3
1
2
4
2
7

1
2
5
3

albina.out
6

15
12
12
10

Concursul Naional de Soft Grigore Moisil , Lugoj 2003

Soluie
Este o problem de backtracking n plan, n care apar cteva elemente n plus:
condiionarea deplasrii albinei n raport cu nlimile florilor i determinarea
suprafeei dreptunghiulare de aria maxim.
Reprezentarea informaiilor
Informaiile despre nlimile florilor se rein ntr-un tablou a. Acesta este
bordat cu o valoare mai mare dect nlimea maxim a florilor pentru a nu permite
ieirea n afara cmpului n timpul procesului de polenizare. n plus se folosete
un tablou auxiliar t, n care sunt marcate cu valoarea 1 florile care au fost
polenizate. Acest tablou este folosit i pentru determinarea zonei dreptunghiulare
de arie maxim care conine numai flori polenizate.
Condiii interne
1.
2.
3.
4.

a[i][j]{1, 2, ..., 100}


t[i][j]{0,1}, i{1, ..., n}, j{1, ..., m}
1 n, m 30
1 h1, h2 20

100

3. METODA BATRACKING

n prima etap se determin toate florile care pot fi polenizate, plecnd de la


floarea iniial. Printr-un algoritm de tip fill sunt marcate n tabloul t toate
florile care pot fi polenizate.
n etapa a doua se determin zona dreptunghiular de arie maxim care conine
doar flori polenizate adic n tabloul t doar valori egale cu 1. Pentru aceasta se
parcurge tabloul t i se determin, pe rnd, cte un element nenul. Acesta va fi
colul din stnga-sus a zonei dreptunghiulare testate. Pstrnd colul constant se
determin, pe rnd, toate elementele nenule din tablou aflate la dreapta (indice de
coloan mai mare) i mai jos (indice de linie mai mare) dect colul respectiv.
Fiecare element nenul detectat va constitui colul din dreapta-jos a unei zone
dreptunghiulare. Se verific dac aceast zon conine numai elemente egale cu 1,
fcndu-se produsul tuturor elementelor din zon, i, n caz afirmativ, se compar
cu aria maxim detectat pn n acel moment, reinndu-se eventual noua arie.
#include <stdio.h>
#define MAX 1000
int dx[4]={-1, 0, 1, 0};
int dy[4]={0, 1, 0, -1};
int t[32][32], a[32][32], n, m, i_prim, j_prim, l_s, l_j;
void citire(void)
{ int i, j;
FILE *f=fopen("albina.in","r");
fscanf(f,"%d %d", &n, &m);
fscanf(f,"%d %d", &i_prim, &j_prim);
fscanf(f,"%d %d", &l_s, &l_j);
for(i=1; i<=n; i++)
for(j=1; j<=m; j++) fscanf(f, "%d", &a[i][j]);
fclose(f);
}
void bordare(void)
{ int i, j;
for(i=0; i<=n+1; i++) a[i][0]=a[i][m+1]=MAX;
for(j=0; j<=m+1; j++) a[0][j]=a[n+1][j]=MAX;
}
void depune(int i, int j)
{ int i_nou, j_nou, l;
t[i][j]=1;
for (l=0; l<4; l++)
{ i_nou=i+dx[l]; j_nou=j+dy[l];
if (t[i_nou][j_nou]==0)
{if ((a[i][j]>=a[i_nou][j_nou])&&
(a[i][j]-a[i_nou][j_nou]<=l_j))
depune(i_nou,j_nou);

3. METODA BACKTRACKING

101

if ((a[i][j]<a[i_nou][j_nou])&&
(a[i_nou][j_nou]-a[i][j]<=l_s))
depune(i_nou,j_nou);
}
}
}
int aria(void)
{
int i, j, k, l, i1, j1;
int Max=0,p;
for(i=1; i<=n; i++)
for(j=1; j<=m; j++)
if(t[i][j])
//pentru fiecare floare polenizata
for(k=i; k<=n; k++)
//colt stanga-sus
for(l=j; l<=m; l++) //se cauta
if(t[k][l])
//o alta floare polenizata
{
//colt dreapta-jos
//in dreptunghiul determinat de aceste doua flori se face
//produsul elementelor (1 - polenizata sau 0 - nu)
p=1;
for(i1=i; i1<=k; i1++)
for(j1=j; j1<=l; j1++)
p*=t[i1][j1];
if(p) //daca toate au fost 1
//am determinat un dreptunghi plin
if((k-i+1)*(l-j+1)>Max)
Max=(k-i+1)*(l-j+1);
//retin maximul aflat pana acum
}
return Max;
}
int main()
{
FILE *g;
citire();
bordare();
depune(i_prim,j_prim);
g=fopen("albina.out","w");
fprintf(g,"%d",aria());
fclose(g);
return 0;
}

102

3. METODA BATRACKING

Collapse
Collapse este un joc foarte popular. Tabla de joc este reprezentat de o zon
dreptunghiular de pe ecran, zona fiind mprit n celule, organizate n N linii i M
coloane. Fiecare celul poate conine o pies roie (identificat prin litera R), verde
(identificat prin litera V) sau albastr (identificat prin litera A).
Acionnd printr-un clic pe o pies, tot grupul de piese corespunztor piesei
respective va disprea.
Grupul unei piese este format din toate piesele care au aceeai culoare cu piesa
respectiv i la care se poate ajunge deplasndu-ne numai pe piese de aceeai
culoare cu piesa respectiv. O deplasare se poate face n 4 direcii (sus, jos, stnga
sau dreapta). Un grup trebuie s conin cel puin dou piese.
Dup ce grupul piesei asupra creia am acionat printr-un clic a disprut, piesele
de pe tabl se prbuesc. Prbuirea se realizeaz executnd, n ordine,
urmtoarele dou operaii:
1. Mai nti, toate piesele rmase cad (sunt deplasate n jos), pentru a umple
golurile de pe coloane; ordinea pieselor pe coloane se pstreaz.
2. Dac o coloan se golete complet, ea va fi eliminat, deplasnd celelalte
coloane ctre stnga, ct este posibil; ordinea coloanelor se pstreaz.
De exemplu, s considerm tabla de joc din figura urmtoare:
R
R
V
V
V
V
A
A
A

R
R
R
V
V
V
A
A
R

A
R
R
R
R
R
A
A
R

R
R
R
R
R
R
R
R
R

V
V
V
R
A
A
V
V
V

R
A
A
R
V
A
V
V
R

V
V
R
R
V
A
A
R
R

Dac executm un clic pe piesa din colul din stnga sus, obinem:
A
V
V
V
V
A
A
A

V
V
V
A
A

A
A

V
V
V

R
A
A

V
V

A
A
V
V
V

V
A
V
V
R

V
A
A
R
R

Apoi piesele se prbuesc. Mai nti cad pentru a umple golurile pe coloane:

103

3. METODA BACKTRACKING

V
V
V
V
A
A
A

V
V
V
A
A

A
A
A

V
V
V
A
A
V
V
V

R
A
A
V
A
V
V
R

R
A
A
V
A
V
V
R

V
V
V
A
A
R
R

V
V
V
A
A
R
R

Apoi se elimin coloanele goale:

V
V
V
V
A
A
A

V
V
V
A
A

A
A
A

V
V
V
A
A
V
V
V

Jocul se termin cnd pe tabla de joc nu se mai pot forma grupuri de piese.
Vasile joac acest joc de muli ani. Niciodat nu joac la ntmplare,
ntotdeauna folosete aceeai strategie. La fiecare pas, Vasile face un clic pe o
pies din cel mai mare grup existent pe tabla de joc. Chiar dac exist mai multe
posibiliti de a alege piesa, el va face clic pe piesa situat pe cea mai din stnga
linie. i dac exist mai multe posibiliti de a alege o pies pe cea mai din stnga
linie, Vasile o va alege ntotdeauna pe cea situat cel mai jos.
Cerin
Scriei un program care s simuleze jocul i care s determine numrul de clicuri pe care le execut Vasile pn la terminarea jocului.
Date de intrare
Fiierul de intrare joc.in conine pe prima linie dou numere naturale
separate printr-un spaiu N M, care reprezint numrul de linii i respectiv numrul
de coloane de pe tabla de joc. Urmeaz N linii, fiecare linie coninnd M caractere
din mulimea {R, V, A}.
Date de ieire
Fiierul de ieire joc.out va conine o singur linie pe care va fi scris
numrul de clic-uri pe care le execut Vasile pn la terminarea jocului.
Restricii
1

N, M 50

104

3. METODA BATRACKING

Exemple
joc.in
3 4
AVVR
AAVV
AVRR

joc.out
3

joc.in
joc.out
8 7
7
RRARVRV
RRRRVAV
VRRRVAR
VVRRAVV
VVRRAAA
AAARVVA
AAARVVR
ARRRVRR
Olimpiada Naional de Informatic, Galai 2005

Soluie
Se repet ct timp se mai pot forma grupuri cu cel puin 2 elemente:
1. Se determin grupurile de pe tabl. Pentru fiecare grup determinat se calculeaz
dimensiunea i se reine dimensiunea maxim, precum i elementul cel mai din
stnga-jos care aparine unui grup de dimensiune maxim.
2. Se terge grupul de dimensiune maxim selectat.
3. Se compacteaz coloanele.
4. Se elimin coloanele goale.
Pentru determinarea/tergerea unui grup se utilizeaz un algoritm de fill.
#include <fstream.h>
#define DMax 52
#define InFile "joc.in"
#define OutFile "joc.out"
#define Dir 4
int dl[]={-1,0,1,0};
int dc[]={0,-1,0,1};
struct poz
{
char cul; //culoarea celulei
int gr; //numarul grupului din care face parte celula
};
poz T[DMax][DMax]; //tabla de joc
int n, m, linmax, colmin, nrclic;
/* linmax si colmin reprezinta coordonatele celulei din
unul dintre grupurile de dimensiune maxima, care se afla
cel mai in stanga jos */
void citire();
void afisare();

105

3. METODA BACKTRACKING

int prelucrare_tabla();
int det_grup(int , int , int , char );
void sterge_grup(int , int , int );
void refa_tabla(int , int );
int main()
{ int dim;
citire();
do
{ linmax=0; colmin=m+1;
dim = prelucrare_tabla();
if (dim>1)
{ nrclic++;
refa_tabla(linmax, colmin);
}
while (dim>1);
afisare();
return 0;
}

void citire()
{ int i, j;
ifstream fin(InFile);
fin>>n>>m; fin.get();
for (i=1; i<=n; i++)
{
for (j=1; j<=m; j++)
{fin>>T[i][j].cul;
fin.get();
}
//bordare
for (i=0; i<=n+1; i++)
T[i][0].gr=T[i][m+1].gr=DMax*DMax+1;
for (j=0; j<=m+1; j++)
T[0][j].gr=T[n+1][j].gr=DMax*DMax+1;
fin.close();
}
int det_grup(int grnum, int i, int j, char ch)
{ int sum=1, k;
if (T[i][j].cul != ch) return 0;
T[i][j].gr = grnum;
for (k=0; k<Dir; k++)
if (T[i+dl[k]][j+dc[k]].gr==0)
sum+=det_grup(grnum, i+dl[k], j+dc[k], ch);
return sum;
}

106

3. METODA BATRACKING

int prelucrare_tabla()
/* identifica toate grupurile si returneaza dimensiunea
grupului maxim */
{ int maxdim = 0, dim, grnum=1, i, j;
for (j=1; j<=m; j++)
for (i=n; i>=1 ; i--)
if (T[i][j].gr == 0 && T[i][j].cul!=' ')
//aceasta celula nu apartine nici unui grup
{
dim = det_grup(grnum, i, j, T[i][j].cul);
//marcam grupul
if (dim > maxdim)
{maxdim = dim; linmax=i; colmin=j;
}
else
if (dim==maxdim)
if (j<colmin) {colmin=j; linmax=i;}
else
if (j==colmin)
if (i>linmax) linmax=i;
grnum++;
}
return maxdim;
}
void sterge_grup(int grnum, int i, int j)
{if (T[i][j].gr == grnum && T[i][j].cul!=' ')
{ T[i][j].cul=' ';
sterge_grup(grnum, i-1, j);
sterge_grup(grnum, i, j-1);
sterge_grup(grnum, i+1, j);
sterge_grup(grnum, i, j+1); }
}
void refa_tabla(int lin, int col)
{ int i, j, i2, j2;
sterge_grup(T[lin][col].gr, lin, col);
for (j=1; j<=m; j++)
{ //prelucram coloana j
for (i=n; i>=1; i--)
if (T[i][j].cul==' ')
{//caut mai sus un element colorat
for (i2=i-1; i2>=1 && T[i2][j].cul==' '; i2--);
if (i2) //am gasit
{T[i][j]=T[i2][j]; T[i2][j].cul=' '; }
else break;
}
}
//eliminam coloanele goale

3. METODA BACKTRACKING

107

for (j=1; j<=m; j++)


if (T[n][j].cul == ' ') //coloana j este vida
{//caut in dreapta o colona nevida
for (j2=j+1; j2<=m && T[n][j2].cul==' '; j2++);
if (j2<=m) //am gasit
//copiez coloana j2 peste coloana j; sterg coloana j2
for (i=1; i<=n; i++)
{T[i][j]=T[i][j2]; T[i][j2].cul=' ';}
else break;
}
for (i=1; i<=n; i++)
for (j=1; j<=m; j++)
T[i][j].gr = 0;
}
void afisare()
{ofstream fout(OutFile);
fout<<nrclic<<endl;
fout.close(); }

3.5. Consideraii finale asupra metodei backtracking


A existat o perioad n evoluia gndirii algoritmice cnd metoda backtracking
era considerat un panaceu. Nu tim s rezolvm o problem? Nu-i nimic! Aplicm
un backtracking! Sigur c aceast metod are avantaje indiscutabile. Aa cum
spuneam la nceputul capitolului, metoda evit generarea tuturor soluiilor posibile,
urmat de verificarea condiiilor problemei pentru fiecare soluie posibil (adic se
poate i mai ru). n plus, rezolvarea unei probleme prin backtracking garanteaz
obinerea soluiei. Numai c timpul de execuie este foarte mare, datorit revenirilor specifice metodei. Uneori timpul de execuie este att de mare nct pentru
dimensiuni mari ale datelor de intrare, este practic imposibil obinerea unei soluii.
n concluzie, cnd trebuie s rezolvm o problem ncercm n primul rnd s
elaborm un algoritm care nu se bazeaz pe backtracking. Dac nu reuim s
elaborm un astfel de algoritm sau un astfel de algoritm nu exist, analizm datele
de intrare. Dac datele de intrare au dimensiuni rezonabil de mici, astfel nct un
algoritm backtracking s furnizeze soluii n timp util, abordm problema n
aceast manier.
Dac ns datele de intrare au dimensiuni mari, ceea ce n practic este inevitabil, o abordare backtracking este inacceptabil. Principiul de baz poate fi rezumat
astfel: dect un algoritm teoretic perfect, dar care s nu furnizeze soluii n timpul
disponibil, mai bine un algoritm bun, care s ofere soluii aproape optime n
timp scurt. Un astfel de algoritm este denumit algoritm euristic. Studiul
algoritmilor euristici este o problem fierbinte n informatic la ora actual.

108

3. METODA BATRACKING

3.6. Probleme propuse


1. Urmrii pas cu pas execuia urmtorului program pentru n=4. Ce va afia pe
ecran programul?
#include <iostream.h>
char x[30];
int n;
void gen(int k)
{ if (k==n) cout<<x<<endl;
else
for (char c='a'; c<'d'; c++)
if (x[k-1]!=c)
{x[k]=c;
gen(k+1); }
}
int main()
{cin>>n;
x[0]='a';
gen(1); return 0;}

2. Care dintre urmtoarele afirmaii sunt adevrate i care sunt false?


a. Metoda backtracking se poate implementa numai cu ajutorul funciilor
recursive.
b. Metoda backtracking evit generarea tuturor soluiilor posibile, urmat de
verificarea condiiilor interne pentru fiecare soluie posibil.
c. Indiferent de problem, aplicarea metodei bactracking conduce la cei mai
eficieni algoritmi.
3. Prin metoda backtracking au fost generate toate posibilitile de a aranja pe un
rnd 4 copii (Ana, Dan, Ion, Maria), astfel nct s nu fie plasai doi biei
unul lng altul. Primele 4 soluii generate sunt:
Ana
Ana
Dan
Dan

Dan
Ion
Ana
Ana

Maria Ion
Maria Dan
Ion Maria
Maria Ion

Care va fi urmtoarea soluie generat?


4. Secvene binare
S se genereze toate secvenele binare de lungime m, n care apar n de 1.
5. Coliere
Scriei un program care s vizualizeze n mod text toate colierele de n (nN*)
mrgele albe, roii, galbene, verzi i negre care se pot construi respectnd
urmtoarele reguli:
nu plasm dou mrgele de aceeai culoare n poziii consecutive;

3. METODA BACKTRACKING

109

nu plasm mrgele albe lng mrgele galbene i nici mrgele verzi lng
mrgele negre;
nu utilizm mai mult de n/2 mrgele roii.
6. Numere cu suma cifrelor dat
S se afieze toate numerele formate din cifre distincte cu proprietatea c suma
cifrelor este S. Valoarea variabilei S se citete de la tastatur. Soluiile vor fi afiate
pe ecran. De exemplu, pentru S=3, se afieaz soluiile 102, 12, 120, 201, 21,
210, 3, 30.
Bacalaureat, 2000
7. Matrice
Fie nN*, n10, n par. S se genereze toate matricele cu n linii i n coloane
avnd componente numere naturale ntre 1 i n astfel nct oricare dou elemente
vecine (pe orizontal sau vertical) s fie de pariti diferite, iar elementele de pe
aceeai linie, respectiv de pe aceeai coloan s fie distincte.
Soluiile vor fi afiate n fiierul matrice.out, ntre dou soluii consecutive
fiind scris o linie goal.
8. Operatori
Se citesc de la tastatur un numr natural n (0<n10) i apoi n valori naturale
a1, a2, ..., an. Afiai pe ecran toate posibilitile de a intercala ntre toate numerele
a1, a2, ..., an operatorii + i astfel nct evalund expresia obinut de la stnga la
dreapta, la fiecare pas rezultatul obinut s fie strict pozitiv. Fiecare soluie se va
afia pe cte o linie. De exemplu, pentru n=3 i valorile a1=3, a2=5, a3=2, se vor
afia soluiile:
3+5+2
3+5-2

9. Examen
Un student primete la un examen n subiecte, numerotate de la 1 la n
(1n20). Pentru fiecare subiect este cunoscut punctajul care se obine rezolvnd
subiectul respectiv (nu se acord punctaje pariale), precum i dificultatea
subiectului. Studentul vrea s obin cel puin un punctaj total P, dar nu poate s
rezolve subiecte cu dificultate > D.
Determinai toate variantele n care studentul poate obine un punctaj
satisfctor.
Fiierul de intrare examen.in conine pe prima linie trei numere naturale
separate prin spaii n, P i D, cu semnificaia din enun. Pe cea de a doua linie se
afl n numere naturale separate prin spaii, reprezentnd, n ordine, dificultile
subiectelor. Pe cea de a treia linie se afl n numere naturale separate prin spaii,
reprezentnd, n ordine, punctajele subiectelor.

110

3. METODA BATRACKING

Fiierul de ieire examen.out va conine cte o linie pentru fiecare variant


generat. Descrierea unei variante este constituit din numerele subiectelor
rezolvate, separate prin cte un spaiu. Dac nu exist nici o variant satisfctoare,
fiierul de ieire va conine pe prima linie mesajul MAI INVATA!.
10. Generare ir
Se citesc de la tastatur dou numere naturale a i b (0<a10, 0<b1000,
3a b). S se genereze cel mai lung ir care are ca prim element valoarea a,
suma elementelor irului este egal cu b i n care orice termen este cel puin
dublul valorii termenului precedent. irul obinut se va afia pe un singur rnd, cu
spaii ntre elementele ce-l formeaz.
Dac exist mai multe iruri cu acelai numr maxim de elemente, se va afia
unul singur, oricare dintre acestea.
De exemplu, pentru a=4 i b=63 se va afia oricare dintre urmtoarele iruri:
4 8 16 35
4 8 17 34

Se observ c irul 4 11 48 respect condiiile din enun, dar nu are numr


maxim de termeni.
Bacalaureat special 2002
11. Rnd
ntr-o clas de n elevi sunt f fete (n,fN*, fn). Fetele sunt numerotate de
la 1 la f, iar bieii de la f+1 la n. S se genereze toate posibilitile de a forma un
rnd din p elevi (pn) astfel nct s nu existe dou fete aezate n rnd una lng
cealalt, respectiv doi biei unul lng cellalt.
12. Generare iruri cresctoare
S se genereze toate irurile strict cresctoare formate din numere naturale cu
proprietatea c primul element din ir este n, iar ultimul element al irului este
n+k. Numerele naturale n i k (0<n<20, 0<k<16) sunt citite de la tastatur.
Fiecare ir generat va fi scris pe o linie, elementele unui ir fiind separate prin cte
un spaiu
De exemplu, pentru n=7 i k=3, se vor afia (nu neaprat n aceast ordine)
irurile:
7
7
7
7

8 9 10
8 10
9 10
10
Bacalaureat 2001

13. Generare iruri de cifre


S se genereze toate irurile formate din n cifre, fiecare ir generat avnd
urmtoarele proprieti:

111

3. METODA BACKTRACKING

conine numai cifre din mulimea {1, 2, 3, 4};


orice dou cifre alturate sunt fie ambele pare, fie ambele impare.
Numrul natural n (3 n 15) se citete de la tastatur. Toate soluiile vor fi
scrise una dup alta, cu spaii ntre soluii, fiecare ir fiind scris fr spaii ntre cifrele
ce-l formeaz.
De exemplu, pentru n=3, se afieaz (nu neaprat n aceast ordine) irurile:
111
422

113
424

131 133
442 444

311

313

331

333

222

224

242

244

Bacalaureat august 2001

14. Tombol
La o tombol sunt n obiecte (numerotate de la 1 la n), care valoreaz v1, v2, ...,
respectiv vn lei. Premiul cel mare trebuie s fie format din obiecte din categorii
diferite, a cror valoare total s fie exact S lei. S se determine n cte moduri se
poate constitui premiul cel mare. Datele se citesc din fiierul de intrare
tombola.in care conine pe prima linie un numr natural nenul n, reprezentnd
numrul de obiecte. Pe cea de a doua linie se afl n numere naturale nenule
separate prin cte un spaiu, reprezentnd, n ordine, valorile celor n obiecte. Pe
urmtoarea linie este scris un numr natural k, reprezentnd numrul de categorii.
Pe ultima linie este sunt scrise n numere cuprinse ntre 1 i k, separate prin spaii
(al i-lea numr de pe linie reprezint categoria din care face parte obiectul i).
Numrul de variante va fi afiat pe ecran.
15. Bare
Se consider o bar de lungime n i m repere de lungimi L1,L2,,Lm. Din bar
trebuie tiate buci de lungimea reperelor date, astfel nct s rezulte din fiecare
reper cel puin o bucat i pierderile s fie nule. Scriei un program care s afieze
toate posibilitile de tiere a barei n condiiile enunate.
16. Banda
Misiunea unui robot este de a lua obiecte de pe o band de asamblare, n
ordinea n care sunt produse i de a le introduce n containere care sunt identice i
au capacitatea gmax.
La fiecare moment de timp numai dou containere sunt disponibile. Dup ce ia
un obiect de pe band, robotul poate alege ntre:
a plasa obiectul n unul dintre cele dou containere disponibile, dac este posibil
(adic dac nu se depete greutatea gmax);
a nchide unul dintre cele dou containere i a deschide unul nou, pentru a pune
n el obiectul.
Atenie! Dup ce a fost nchis un container, acesta este sigilat i nu poate fi
redeschis.

112

3. METODA BATRACKING

Scriei un program care s determine numrul minim de containere necesar


pentru a transporta obiectele de pe banda de asamblare dac se cunoate n numrul
lor, greutile acestora gi (i =1, , n) precum i capacitatea gmax a unui
container.
Date de intrare
Fiierul de intrare banda.in conine pe prima linie dou numere naturale
separate prin spaiu n gmax, reprezentnd numrul de obiecte i capacitatea unui
container. Pe cea de a doua linie se afl n numere naturale separate prin spaii g1
g2 gn, reprezentnd greutile celor n obiecte.
Date de ieire
Fiierul de ieire banda.out va conine pe prima linie numrul minim de
containere necesare transportului.
Restricii
n 25
0 < gmax 100
0 < gi 100

Exemplu
banda.in
6 8
4 2 5 3 5 4

banda.out
3
Olimpiada Municipal de Informatic, Iai 2004

17. Puncte
Fie n un numr natural (n20) i P1, P2, ..., Pn puncte n plan, avnd de
coordonate ntregi. S se determine o modalitate de colorare a celor n puncte,
folosind un numr minim de culori, astfel nct oricare dou puncte situate la
distan D s fie colorate diferit.
18. Concurs
Cei N elevi, numerotai de la 1 la N, din tabra olimpicilor informaticieni de la
Costineti doresc s se ntreac ntr-un campionat pe nisip de tras la frnghie.
Pentru aceasta ei se mpart n P echipe, dar pentru ca ntrecerea s fie ct mai
echilibrat, echipele trebuie s fie ct mai apropiate ca greutate. Greutatea unei
echipe este dat de suma greutilor componenilor ei.
Cerin
Cunoscnd greutile g1, g2, ..., gN ale celor N elevi, s se formeze cele P echipe
astfel nct echipele s fie ct mai echilibrate, adic suma diferenelor de greutate
dintre oricare dou echipe trebuie s fie minim.

113

3. METODA BACKTRACKING

Date de intrare
Fiierul de intrare concurs.in va conine pe prima linie valorile N i P
separate printr-un spaiu. Pe linia a doua se gsesc cele N greuti separate prin cte
un spaiu.
Date de ieire
Fiierul de ieire concurs.out va conine pe prima linie valoarea minim a
sumei diferenelor de greutate dintre oricare dou echipe. Urmtoarele P linii vor
conine cele P echipe, fiecare linie coninnd indicii membrilor unei echipe,
separai prin cte un spaiu.
Restricii

2 N 10
2 P 6
P N
40 gi 99, 1 i N
n fiecare echip trebuie s existe cel puin un elev.

Exemplu
concurs.in
7 3
11 20 30 39 50 61 70

concurs.out
24
1 2 7
4 5
3 6

Explicaii
Greutatea echipei E1 este 101. Greutatea
echipei E2 este 89. Greutatea echipei E3
este 91. Deci (E1-E2)+(E1-E3)+(E3-E2)=
12+10+2=24

19. Problema bilei


Un teren este reprezentat ca o matrice T, cu n linii i m coloane, elementele
matricei reprezentnd cotele diferitelor poriuni de teren. n poziia iniial
(xb,yb) se afl o bil. tiind c bila nu se poate deplasa dect ntr-o poriune de
teren nvecinat (pe direciile N, NE, E, SE, S, SV, V, NV) cu cot strict inferioar
poziiei pe care se afl, scriei un program care s determine toate traseele pe care
le poate urma bila pentru a iei din teren.
20. Sritura calului
Pe o tabl de ah de dimensiune n (nN*) se afl plasat un cal n colul din
stnga sus. Afiai toate posibilitile calului de a parcurge toat tabla de ah, fr a
trece de dou ori prin aceeai poziie.
21. Explorarea Labirintului
Un labirint este reprezentat ca un tablou bidimensional. Pereii labirintului sunt
marcai cu 'X', culoarele labirintului fiind marcate cu spaii. Problema este de a
determina toate punctele labirintului care pot fi vizitate ncepnd cu o poziie
iniial (de start) marcat prin caracterul '*'.

114

3. METODA BATRACKING

22. Joc
Exist i jocuri care pot fi jucate de un singur juctor. Un astfel de joc este
descris mai jos.
O tabl rectangular de dimensiuni NxM este plin cu litere mari a alfabetului
(A-Z). La nceputul jocului n colul din stnga sus al tablei este plasat o pies. n
fiecare moment, juctorul poate muta aceast pies ntr-o poziie vecin (sus,
dreapta, jos, stnga), cu singura restricie ca n poziia respectiv s nu existe o
liter peste care piesa a mai trecut. Scopul jocului este de a menine piesa n joc ct
mai mult posibil. Jocul se oprete cnd piesa nu mai poate fi mutat ntr-o poziie
valid i se oprete ntr-o poziie n care exist o liter peste care piesa a mai trecut.
Scriei un program care determin numrul maxim de mutri pe care le poate
face juctorul.
Date de intrare
Prima linie a fiierului de intrare joc.in conine dou valori ntregi N i M,
separate printr-un singur spaiu, reprezentnd dimensiunile tablei de joc.
Urmtoarele N linii conin fiecare cte M caractere reprezentnd tabla de joc.
Date de ieire
Fiierul de ieire joc.out conine o singur linie pe care se afl numrul
maxim de mutri pe care le poate face juctorul.
Restricii
1 N, M 30
Exemple
joc.in

joc.out

joc.in

joc.out

joc.in

joc.out

2 4
CAAB
ADCB

5 5
IEFCJ
FHFKC
FFALF
HFGCF
HMCHH

10

3 6
HFDFFB
AJHGDH
DGAGEH

.campion 2003

23. Calul i Regele


Un cal i un rege se afl pe o tabl de ah. Unele dintre cmpuri sunt arse,
poziiile lor fiind cunoscute. Calul nu poate clca pe cmpuri arse, iar orice
micare a calului pe un nou cmp, bineneles nears, face ca acesta s devin ars.
Scriei un program care s determine dac exist o succesiune de mutri prin care
calul s ajung la rege i s revin n poziia sa iniial, cu regele n spate.
24. Popularea acvariului
Dac dorim s crem un acvariu cu peti exotici, trebuie s cerem avizul unui
expert pentru a nu ajunge n situaia n care s cumprm tipuri de peti care nu pot
coexista n acvariu.

3. METODA BACKTRACKING

115

Fiind date numrul maxim n de tipuri de peti i suma S care poate fi cheltuit
pentru investiie, se cere s se stabileasc numrul maxim de tipuri compatibile de
peti care se pot cumpra. Pentru acest numr, se cere suma maxim folosit (dar
nu mai mult de S), tiind c se cumpr cte un singur pete din fiecare tip.
Scriei un program care citete din fiierul de intrare 'acv.in' :
de pe prima linie S, suma de bani disponibil (S1000);
de pe a doua linie n, numrul de specii (n30);
de pe a treia linie, n ordine, preul fiecrei specii de peti;
pe fiecare din urmtoarele linii se specifica cte o pereche de specii de peti
(separate printr-un spaiu) care nu pot coexista n acelai timp n acvariu.
n fiierul acv.out vor fi afiate numrul maxim de specii ce pot fi
cumprate, suma maxim cheltuit, precum i speciile cumprate n aceste condiii.
25. Rma lacom
Se d o reea rectangular de dimensiune mxn (0<m<101, 0<n<101). n
anumite noduri, ale cror coordonate se citesc din fiierul de intrare, se afl
substane nutritive (SN) n cantiti precizate. O rm se poate deplasa orizontal sau
vertical, pornind dintr-un nod ce conine SN. Deplasarea ntre dou noduri alturate
presupune pierderea unei uniti de SN. Trecerea printr-un nod ce conine SN
presupune ctigarea ntregii cantiti de SN din nod. S se stabileasc un nod de
plecare i un traseu de deplasare astfel nct:
rma s culeag toate cantitile de SN;
cantitatea final de SN ctigat de rm s fie maxim.
Iniial rma nu are SN i nu se poate deplasa fr SN. Dac nu este posibil
culegerea tuturor cantitilor de SN se va afia mesajul Rama moare.
Baraj, Focani, 1995

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