Documente Academic
Documente Profesional
Documente Cultură
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
3. METODA BACKTRACKING
69
70
3. METODA BATRACKING
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;}
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; }
}
?
...
...
n-2
n-1
lg-3
lg-2
lg-1
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
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
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
...
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
#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
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
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
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; }
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
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;}
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
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
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.
100
3. METODA BATRACKING
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
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
108
3. METODA BATRACKING
Dan
Ion
Ana
Ana
Maria Ion
Maria Dan
Ion Maria
Maria Ion
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
8 9 10
8 10
9 10
10
Bacalaureat 2001
111
3. METODA BACKTRACKING
113
424
131 133
442 444
311
313
331
333
222
224
242
244
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
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
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
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