Documente Academic
Documente Profesional
Documente Cultură
Cu totii stim ca Backtracking este una din cele mai cunoscute tehnici de
programare. Ideea din spatele acestui algoritm este de a genera toate solutiile posibile si a le
abandona in cazul in care observa ca nu indeplinesc conditiile necesare. Datorita generarii tuturor
solutiilor, complexitatea algoritmului este foarte mare, dar duce sigur la generarea tuturor
posibilitatilor valide. Din aceasta cauza, e o tehnica foarte cunoscuta in randul programatorilor (in
special a celor care participa la concursuri si olimpiade de informatica) deoarece este considerata
solutia ce trebuie abordata in cazul in care nu ai nici o idee.
Structura unei functii backtracking
void back(int k)
{
if(reject_sol(k)) return;
if(accept_sol(k)) show_sol(k);
for(i=0;i<n;i++)
{
v[k]=set();
back(k+1);
v[k]=unset();
}
}
Generarea tuturor permutarilor
Problema : Sa se genereze toate permutarile multimii {1, 2, …N}, in ordine lexicografica.
Solutie : Din moment ce problema ne cere generarea tuturor solutiilor, este evident ca vom avea
nevoie de o abordare backtracking.
#include<cstdio>
int a[10],b[10];
int main()
{
freopen("permutari.in","r",stdin);
freopen("permutari.out","w",stdout);
int n;
scanf("%d",&n);
back(1,n);
fclose(stdin); fclose(stdout);
return 0;
}
Generarea tuturor combinarilor de n luate cate k
Problema : Sa se genereze toate combinarile de N luate cate K in ordine lexicografica.
Solutie : Din moment ce si aceasta problema ne cere generarea tuturor posibilitatilor este evident ca
solutia este una ce are nevoie de o abordare backtracking.
#include<cstdio>
int a[19],b[19];
int main()
{
freopen("combinari.in","r",stdin);
freopen("combinari.out","w",stdout);
int n,k;
scanf("%d %d",&n,&k);
back(1,n,k);
fclose(stdin); fclose(stdout);
return 0;
}
Aplicatii Backtracking
1. Generarea aranjamentelor
2. Problema damelor
3. Problema turelor
4. Generarea produsului cartezian a n multimi
5. Sa se genereze n perechi de parantezari care se inchid corect
6. Cel mai lung prefix
Concluzie
Aceasta metoda este extrem de raspandita si de utila in cazul problemelor in care generarea tuturor
solutiilor este necesara. De asemenea, in cazul concursurilor este una din cele mai populare
modalitati de “furare” a catorva puncte.
Referinte
http://infoscience.3x.ro/c++/pbbacktracking.html
http://infoarena.ro/problema/combinari
http://infoarena.ro/problema/permutari
http://en.wikipedia.org/wiki/Backtracking
http://www.cse.ohio-state.edu/~gurari/course/cis680/cis680Ch19.html
Tags:
• backtracking
• problema damelor
• probleme rezolvate
//problema damelor
#include<iostream.h>
#include<conio.h>
#include<math.h>
int st[20],n,k;
void init()
{st[k]=0;}
int succesor()
{if (st[k]<n)
{st[k]++;
return 1;
}
else return 0;}
int valid()
{for(int i=1;i<k;i++)
if(st[i]==st[k] || abs(st[k]-st[i])==abs(k-i)) return 0;
return 1;}
int sol()
{return (k==n);}
void tipar()
{for(int i=1;i<=n;i++) cout<<st[i];
cout<<endl;
}
void bkt()
{int as;k=1;
init();
while(k>0)
{
do {} while ((as=succesor()) && !valid());
if (as)
if (sol()) tipar();
else {k++;init();}
else k--;
}
}
main()
{cout<<"n=";cin>>n;
bkt();
getch();
}
permutari
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
int x[100],n,k;
//k este este nivelul din stiva (indexul - vetorul solutie),curent
int e_valid()
{for(int i=1;i<=k-1;i++)//parcurg nivelurile anterioarenivelului curent
if(x[i]==x[k])
return 0;
return 1;
}
void afisare()
{for(int i=1;i<=n;i++)
cout<<x[i]<<" ";
cout<<endl;
}
void back()
{k=1; //pe primul nivel initial
while(k>0)//cand k va descreste la 0 algoritmul se incheie
if(x[k]<n)
{x[k]++;
if(e_valid())//daca elementul incarcat este valid
if(k==n)//verific daca am ajuns la solutia completa.
afisare();
else //daca nu am solutia completa urc in stiva (maresc vectorul, adica pe k)
{k++;
x[k]=0;}
}
else
k--;
}
void main()
{clrscr();
cout<<"n=";
cin>>n;
back();
getch();
}
17. N copii se aseaza in cerc. Se cunosc numele celor n copii. Sa se gaseasca toate posibilitatile
de rearanjare in cerc.
18. N copii se aseaza in sir indian. Se cunosc numele celor n copii. Sa se gaseasca toate
posibilitatile de aranjare in sir astfel incat un baiat sa urmeze dupa cel mult doua fete
alaturate.
19. N copii au fost asezati in sir indian. Se cunoaste configuratia initiala. Sa se reaseze copiii
astfel incat fiecare copil sa urmeze dupa un alt copil, diferit de cel din configuratia initiala.
20. Se citeste un numar. Sa se genereze toate numerele avand aceleasi cifre ca el. Care este cel
mai mare?
21. N copii au fost asezati in sir indian. Se cunoaste configuratia initiala. Sa se reaseze copiii
astfel incat fiecare copil sa se situeze intre alti copii, diferiti de cei din configuratia initiala.
22. Plata unei sume in bancnote de n tipuri. Solutia cea mai lunga (scurta)
23. Problema drapelelor. Sa se afiseze ca drapel
24. Sa se genereze anagramele unui cuv
25. Sa se genereze toate triunghiurile de perimetru n
26. Intre n persoane care stau pe scaune s-au iscat conflicte. Acestea stau pe scaune numerotate
de la 1 la n. Scrieti un program care sa afiseze toate modurile posibile de reasezare a
persoanelor astfel incat sa nu se gaseasca alaturi doua persoane in conflict.
27. Sa se genereze toate matricile binare (avand 0 si 1) simetrice cu nxn componente.
28. Sa se genereze o secventa de n sunete avand lungimea p care respecto o anumita conditie
29. La un spectacol trebuie sa interpreteze cate o poezie copiii A, B, C, D, E astfel incat copilul
D sa recite inainte de A si B. Sa se genereze toate posibilitatile de recitare a poeziilor.
30. Sa se genereze toate numerele de lungime n formate doar cu cifre pare / impare
31. Scrieti un program care sa afiseze toate numerele de n (n<=10) cifre, formate numai din cifre
distincte si care sunt divizibile cu 4.
32. Sa se aranjeze in toate modurile elementele unui vector a[1],a[2]…a[n] formand secvente de
lungime p, astfel incat fiecare element sa apara de cel mult doua ori
33. Sa se genereze toate cuvintele de lungime p, distincte / nedistincte, care se pot forma cu
literele alfabetului dintr-o multime data
34. Pe o tabla de dimensiune nxn se gasesc n regi. Sa se gaseasca toate posibilitatile de aranjare
a regilor pe tabla astfel incat oricare 2 regi sa nu se atace. Obs. Fiecare rege se va gasi pe alta
linie.
35. Problema partitiilor unui numar
36. Submultimile unui numar
37. a) Fie sirul primelor n numare naturale (n citit de la tastatura). Sa se insereze inainte de
fiecare semnul + sau minus. Pentru fiecare solutie astfel generata se va afisa valoarea
expresiei. Ex pt n =3:
+1+2+3=6
+1+2-3=0
+1-2+3=2 etc
b) sa sedetermine solutiile pentru care expresia este egala cu x. Daca nu exista solutii sa se
afiseze un mesaj
38. a) Fie n numare naturale (n citit de la tastatura) citite de la tastatura. Sa se insereze inainte de
fiecare semnul + sau minus. Pentru fiecare solutie astfel generata se va afisa valoarea
expresiei. Ex pt n =3 si numerele 2 5 4 se vor genera expresiile:
+2+5+4=11
+2+5-4=3
+2-5+4=1 etc.
b) sa sedetermine solutiile pentru care expresia este egala cu x. Daca nu exista solutii sa se
afiseze un mesaj
39. La o cofetarie se comercializeaza n sortimente de prajituri. Sa se determine toate variantele
de a face pachete cu cate p prajituri diferite. Scrieti un program care permite citirea de la
tastatura a celor n sortimente de prajituri si afiseaza variantele solutie precum si numarul
acestora.
40. Fiind data o multime de n cuburi, fiecare cub fiind caracterizat de lungimea laturii si
culoarea sa, sa se scrie un program care sa genereze toate turnurile care se pot forma cu p
cuburi astfel incat doua cuburi vecine sa nu aiba aceeasi culoare iar deasupra unui cub sa nu
se poata aseza un cub cu latura mai mare.
41. Un grup de copii are la dispozitie n cartonase cu n cuvinte disticte pentru jocul "cerc de
cuvinte". In acest joc un copil trebuie sa spuna un cuvant care sa aiba primele doua litere
identice cu ultimele doua ale cuvantului spus de predecesorul lui. fiind dat un cuvant de
inceput pentru joc, afisati varianta cu cele mai multe cuvinte care se pot obtine cu ajutorul
cartonaselor date. Observatie: un sir de cuvinte nu va contine un cuvant de mai multe ori.
42. O persoana a uitat numarul de telefon al unui prieten. Stie doar ca numarul are 6 cifre, incepe
cu 4 si contine 3 zerouri dintre care doua sunt alaturate. fisati toate variantele pe care trebuie
sa le incerce pentru a vorbi cu prietenul sau.
43. La o masa rotunda sunt n persoane de diverse nationalitati, pentru fiecare persoana
precizandu-se doua limbi straine cunoscute de ea. Se cere sa ajutati organizatorii mesei
rotunde sa aranjeze persoanele astfel incat fiecare sa poata conversa atat cu cea din stanga cat
si cu cea din dreapta.
44. Sa se genereze numerele mai mici decat n citit care trecute in baza 2 au in componenta lor
exact p cifre de 1.
45. Teste la geografie. Pentru lucrarea de control profesoara de geografie a pregatit n teste. In
clasa sunt p elevi (p>n). Sa se genereze toate posibilitatile de a imparti testele celor p elevi
astfel incat fiecare test sa fie rezolvat de macar un elev.
46. Sa se genereze toate drapelele tricolore care se pot forma cu n culori (eventual impunand
conditii : in mijloc sa fie o anumita culoare, o culoare sa nu stea langa alta culoare etc
47. Produsul cartezian a n multimi impunand conditia ca suma elementelor dintr-o solutie sa fie
egala cu un S citit
48. Sa se genereze toate submultimile de cate k elemente care se pot forma cu numerele 1,2…n
(sau a[1],a[2]…a[n]), cu conditia ca fiecare element sa fie divizibil cu un numar d dat.
49. Sa se rearanjeze elementele unui vector a[1],a[2]…a[n] in toate modurile posibile, astfel
incat oricare doua alaturate sa nu fie consecutive in sirul initial
50. Sa se aranjeze n margele de m culori astfel incat oricare doua margele alaturate sa aiba culori
diferite
51. Sa se genereze toate numerele de lungime p care sunt supermultiple de p (atat numerele cat
si toate prefixele lor sa fie multiplu de p)
52. La un festival de muzica usoara s-au inscris n melodii codificate cu numere de la 1 la n.
Stiind ca in prima zi intra in concurs k melodii, sa se afiseze toate posibilitatile de a stabili
ordinea intrarii in concurs a melodiilor in prima zi, stiind ca melodiile de coduri c1 si c2
trebuie sa intre in prima zi, a doua respectiv penultima
53. Sa se afiseze toate numerele de lungime p<=9 cu proprietatea ca au suma cifrelor egala cu x
dat
54. Sa se afiseze toate submultimile cu p elemente dintre elementele a[1],a[2]…a[n] cu
proprietatea ca suma elementelor din multime este un numar divizibil cu x dat
55. Sa se afiseze toate modurile in care se poate forma un grup de p persoane dintr-un grup de n
persoane, dintre care l persoane sa fie femei
56. La un concurs se prezinta n concurenti din m tari. Sa se stabileasca ordinea intrarii in concurs
a celor n concurenti astfel incat doi concurenti din aceeasi tara sa nu urmeze unul dupa altul
57. Sa se aranjeze elementele multimii {A,R,G,V} in grupuri de cate n (n par) astfel incat doua
caractere identice sa nu fie alaturate si R sa apara de exact n/2 ori
58. Sa se genereze toate numerele de lungime n formate doar cu cifre pare / impare
59. Sa se genereze toate numerele de lungime n divizibile cu x dat
60. Sa se determine toate numerele de lungime n care sunt egale cu inversele lor
61. Sa se determine toate modurile in care poate fi capsat un bilet, stiind ca pozitiile posibile sunt
de forma:
***
***
***
si se pot perfora p1<=k
Biletul poate fi introdus pe oricare din fete.
1. Sunt 2n copii de inaltimi diferite. Sa se aseze copiii pe 2 randuri astfel:
- pe primul rand copiii sa fie asezati in ordinea crescatoare a inaltimii
- copiii de pe al doilea rand sa fie mai inalti decat cei din fata lor
2. un pion se poate deplasa pe o tabla dreptunghiulara cate o casuta pe orizontala sau pe
varticala. Se dau coordonatele initiale, coordonatele finale si de cate ori trebuie sa treaca
pionul prin fiecare casuta. Sa se genereze toate solutiile. De fiecare data se afiseaza traseul de
parcurs.
Exemplu
112110
002220
000010
000000
din 1 1 pana in 1 5 o solutie este:
1 1, 1 2, 1 3, 2 3, 2 4 , 2 5, 3 5, 2 5, 2 4, 2 3, 1 3, 1 4, 1 5.
62. Sa se genereze toate solutiile naturale nenule ale ecuatiei 4x+y+3yz=100
63. sa se genereze toate codurile morse de lungime n coduri reprezentate prin ‚–‚ sau ‚.’ Astfel
incat intr-o secventa sa nu existe doua puncte alaturate. Pentru fiecare semn se va genera un
sunet.
64. Sa se genereze toate secventele in cod binar de lungime n. Pentru fiecare secventa se va
genera numarul asociat in baza 10.Sa se genereze toate codurile
65. Sa se genereze toate numerele naturale ale caror cifre se gasesc printre cifrele lui x citit si au
lungimea cel mult egala cu lungimea lui x. Cifrele se pot repeta
66. La Masa Rotunda sunt n cavaleri. Fiecare dintre ei are cel putin un dusman printre ceilalti.
Sa se gaseasca toate posibilitatile de a-i aseza la masa astfel incat doi vavaleri dusmani sa nu
fie vecini. Se citesc cele m perechi de dusmani de la tastatura (fisier)
67. Fie o harta cu n tari. M perechi de tari sunt vecine (se cunosc perechile de tari vecine). Sa se
coloreze harta astfel incat oricare doua tari alaturate sa fie colorate diferit.
68. Un comis voiajor trebuie sa ajunga la n case. Intre cele n case exista m dumuri (un drum este
dat ca o pereche de case vecine). Sa se genereze toate posibilitatile de parcurgere a celor n o
singura data case astfel incat comis voiajorul sa ajunga inapoi de unde a plecat. Casa de la
care se pleaca este casa p.
69. In cate moduri poate ajunge un pion de pe prima linie a unei table bidimensionale cu n linii
si n coloane pe ultima linie a tablei. Se cunoaste coloana de plecare p. Pionul se poate
deplasa numai pe o casuta alaturata si numai pe o linie mai mare.
70. Sa se determine partitiile unui numar pt care suma inverselor obtinute este subunitara. Ex.
n=5 3+2=5 si 1/3+1/2<1.
71. Se citeste un numar natural. Sa se determine toate numerele avand aceleasi cifre sau o parte
din cifre si care sunt divizibile cu p citit
72. Sa se determine toate numerele cu cifre distincte. Cate astfel de numere sunt?
73. Sa se genereze toate numerele avand cifre distincte de la 0 la p. Numarul de cifre poate fi
>=1 si <= p+1. Cate astfel de numere sunt?
74. Sa se determine cate numere cu cifre distincte sunt.
Backtracking in plan
Fie urmatoare problema: un soricel se gaseste intr-un labirint de forma dreptunghiulara cu m linii si
n coloane. Peretii sunt marcati cu 1 si culoarele cu 0. Se cunosc coordonatele initiale ale soricelului:
Li, Ci. Sa se determine toate posibilitatile pe care le are soricelul pentru a iesi din labirint. Soricelul
poate avansa pe 4 directii cate o celula (sus, dreapta , jos, stanga).
O astfel de problema presupune o abordare Backtracking in plan. Traseul soricelului va fi
retinut de un vector cu doua campuri: coordonatele x si y. Vom defini un tip struct:
struct pozitie
{int x,y;};
si vom declara un vector care retine drumul: pozitie d[50];
Pentru generarea unui drum vom defini un subprogram recursiv oid ies(int x,int y) care
primeste ca parametri coordonatele unei componente din matrice. Initial se apeleaza pentru
coordonatele initiale ale soricelului. O componenta din matrice va putea apartine drumului daca
evident este culoar (a[x][y]=0). O celula a matricii determinata ca apartinand drumului se marcheaza
cu 2 (pentru a preveni ciclarile):
a[x][y]=2;
Se incarca valoarea corespunzatoare in vectorul d pe nivelul curent:
d[k].x=x;
d[k].y=y;
De fiecare data cand s-a determinat o noua celula ca apartinand drumului se determina daca
s-a ajuns la solutie (conditie care difera de la o problema la alta).
In cazul probemei noastre se iese din labirint cand se ajunge la linia 0 sau coloana 0 sau linia
m+1 sau coloana n+1. testul este:
if((x<1)||(x>m)||(y<1)||(y>n))
tipar(k);
In caz afirmativ se tipareste (se afiseaza vectorul d si/sau matricea a) altfel (daca solutia este
incompleta) se incearca parcurgerea, pe rand, a celor 4 celule alaturate. Acest lucru se realizeaza
prin autoapelul functiei ies pe cele patru directii:
ies(x-1,y);
ies(x,y+1);
ies(x+1,y);
ies(x,y-1);
Observatie: vectorul d functioneaza ca o stiva cu doua campuri.
La revenire din apel se elibereaza celula pentru a o putea accesa si in cadrul altor prelucrari:
a[x][y]=0 si se elibereaza componenta drumului k=k-1 (practic se coboara in stiva).
void ies(int x,int y)
{if(a[x][y]==0)
{k++;
a[x][y]=2;
d[k].x=x;
d[k].y=y;
if((x<1)||(x>m)||(y<1)||(y>n))
tipar(k);
else
{ies(x-1,y);
ies(x,y+1);
ies(x+1,y);
ies(x,y-1);
}
a[x][y]=0; //la revenire din apel demarchez celula pentru a o putea
//accesa si in cadrul altei prelucrari
k--; //eliberez componenta din vectorul drumului
}
}
Fie urmatorul labirint: m=6 n=10 Li=4, Ci=3
1111011111
1111011111
1111011111
1100000000
1111111011
1111111011
Solutiile vor fi:
solutia 1
(4,3) (4,4) (4,5) (3,5) (2,5) (1,5) (0,5)
1111211111
1111211111
1111211111
1122200000
1111111011
1111111011
solutia 2
(4,3) (4,4) (4,5) (4,6) (4,7) (4,8) (4,9) (4,10) (4,11)
1111011111
1111011111
1111011111
1122222222
1111111011
1111111011
solutia 3
(4,3) (4,4) (4,5) (4,6) (4,7) (4,8) (5,8) (6,8) (7,8)
1111011111
1111011111
1111011111
1122222200
1111111211
1111111211
Programul complet este:
#include<fstream.h>
#include<conio.h>
struct pozitie
{int x,y;};
int a[20][20];//labirintul
int k,n,m,Li,Ci,nr_sol;
pozitie d[50];
void afis_mat() //afiseaza matricea
{cout<<endl;
for(int i=1;i<=m;i++)
{for(int j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl;}
}
void tipar(int k) //tipareste vectorul drum
{nr_sol++;
cout<<"solutia "<<nr_sol<<endl;
for(int i=1;i<=k;i++)
cout<<"("<<d[i].x<<','<<d[i].y<<") ";
afis_mat();
getch();
cout<<endl;}
void ies(int x,int y) //genereaza drumul
{if(a[x][y]==0)
{k++;
a[x][y]=2;
d[k].x=x;
d[k].y=y;
if((x<1)||(x>m)||(y<1)||(y>n))
tipar(k);
else
{ies(x-1,y);
ies(x,y+1);
ies(x+1,y);
ies(x,y-1);
}
a[x][y]=0; //la revenire din apel demarchez celula pentru a o putea
//accesa si in cadrul altei prelucrari
k--;//eliberez componenta din vectorul drumului
}
}
void citire()
{ fstream f;
f.open("labir.txt",ios::in);
if(f)
cout<<"ok";
else
cout<<"eroare la deschidere";
1 14 99 20
20 33
24 19 22 15
15 10
10
13
13 88 25
23 44 21
21
18
18 23
25 66 11
11 16
16
77 12
12 17
17 22
22 55
3.Ali Baba
Ali Baba i-a surprins pe cei 40 de hoti, in timp ce cotrobaiau printre comorile lui. Hotii erau
multi, el era singur, asa ca a incercat sa negocieze cu ei. Avea o ladita speciala, pe care era notat
numarul de diamante aflate in aceasta, un numar avnd cel mult 40 de cifre, intr-o baza b. Ali Baba a
propus conducatorului hotilor sa elimine din numar b cifre, dupa care poate sa plece cu atatea
diamante cate reprezinta numarul ramas.
Hotul, mai intai a stabilit valoarea cea mai mica posibila b, deoarece a vrut sa stabileasca un numar
cat mai mic posibil de cifre pe care urmeaza sa le elimine. Apoi a inceput tierea cifrelor. In timpul
eliminarii a urmarit ca numarul ramas sa fie cat se poate de mare.
Scrieti un program care il ajuta pe hot(Ali Baba are destule comori…).
Date de intrare
Pe prima linie a fisierului de intrare ALIBABA.IN se afla un sir de cifre, nedespartite prin spatii.
Date de iesire
Pe prima linie a fisierului de iesire ALIBABA.OUT se va scrie pe fiecare cate un numar,
reprezentand numasrul ramas dupa eliminarea unei cifre.
Restrictii si precizari 2<=b<=10
Exemplu
ALIBABA.IN
323332112
ALIBABA.OUT
4
33332112
333212
33322
3332
Diferitele variante ale metodei backtracking nu schimbă esenţa ei care constă în faptul că este
reprezentabilă pe un arbore care este parcurs "coborând" în arbore numai dacă există şanse de a
ajunge la o soluţie rezultat.
În continuare, problemele care vor fi prezentate vor urma o schema generală şi anume:
- se va testa dacă am obţinut o soluţie, situaţie în care acesta se va reţine;
- dacă nu am obţinut soluţie se încearcă plasarea unui nou element în vectorul soluţie cu
respectarea condiţiilor de continuare;
- dacă nu se reuşeşte plasarea unui nou element şi spaţiul valorilor posibile de plasat s-a epuizat, se
revine la poziţia anterioară şi se încearcă să se plaseze pe ea un alt element.
Faptul că după plasarea unui element în vectorul soluţie algoritmul presupune plasarea unui
element pe poziţia imediat următoare, adică de fapt reluarea algoritmului, conduce posibilitatea
abordării recursive a algoritmilor de tip backtracking. Acest lucru permite o scriere mult mai scurtă
şi mai simplă a algoritmilor şi apoi a programelor care îi implementează. Astfel, general, un
algoritm backtracking poate fi prezentat astfel:
Subalgoritm back (k)
pentru fiecare valoare i din multimea Sk execută
xk←i
dacă X respectă condiţiile interne atunci
dacă X este solutie atunci
afisează X
altfel
apelează back(k+1)
sfdacă
sfdacă
sfpentru
În funcţie de problema concretă, în algoritmul descris mai sus se vor modifica doar instrucţiunea
pentru, condiţiile interne şi cele de soluţie, structura algoritmului păstrându-se.
Probleme de generare. Oportunitatea utilizării metodei backtracking
Problemele care se rezolvă prin metoda backtracking pot fi împărţite în mai multe grupuri de
probleme cu rezolvări asemănătoare, in funcţie de modificările pe care le vom face în algoritm.
Principalele grupuri de probleme sunt:
a) probleme în care vectorul soluţie are lungime fixă şi fiecare element apare o singură dată în
soluţie;
b) probleme în care vectorul soluţie are lungime variabilă şi fiecare element poate să apară de mai
multe ori în soluţie;
c) probleme în plan, atunci când spaţiul în care ne deplasăm este un tablou bidimensional.
Vom prezenta în cele ce urmează câteva probleme care pac parte din primul grup. Cele mai
cunoscute sunt:
• generarea permutărilor unei mulţimi
• generarea aranjamentelor unei mulţimi
• generarea submulţimilor unei mulţimi
• generarea submulţimilor cu m elemente ale unei mulţimi (combinări)
• generarea produsului cartezian a n mulţimi
• generarea tuturor secvenţelor de n (par) paranteze care se închid corect.
• colorarea ţărilor de pe o hartă astfel încât oricare două ţări vecine să aibă culori diferite
• aranjarea a n regine pe o tablă de şah de dimensiune n fără ca ele să se atace.
Toate problemele din acest grup au particularitatea că soluţia se obţine atunci când vectorul soluţie
ajunge să conţină un anumit număr de elemente.
Vom exemplifica modul de lucru al metodei backtracking pentru problema damelor.
Aranjarea reginelor. Dându-se o tablă de şah de dimensiune nxn (n>3) să se aranjeze pe ea n
regine fără ca ele să se atace. Reamintim că o regină atacă linia, coloana şi cele 2 diagonale pe care
se află. În figura de mai jos celulele colorare mai închis sunt atacate de regina poziţionată unde
indică litera “R”.
Problemele în plan necesită parcurgerea unui tablou unidimensional, iar cele mai cunoscute sunt:
• parcurgerea tablei de şah cu un cal, fără a trece de două ori prin aceeaşi poziţie
• găsirea ieşirii dintr-un labirint
Problemele care se rezolvă prin metoda backtracking în plan au ca cerinţă deplasarea în tablou, pe
linii, coloane sau diagonale sau prin săritură (de obicei săritura calului) dintr-un punct în alt punct
al tabloului sau pe frontieră (prima linie sau coloană, ultima linie sau coloană) eventual respectând
anumite condiţii de deplasare. Dacă ne găsim într-un anumit punct iar cerinţa este de a ne deplasa
în unul din cei opt vecini ai lui vom utiliza pentru acest lucru două cicluri for de la –1 la 1 cu care
valori vom modifica coordonata punctului curent. Dacă deplasarea este permisă numai pe linii
condiţia de respectat este ca suma în valoare absolută pentru cei doi indici să fie 1, iar pentru
deplasarea pe diagonală 2. De asemenea se mai impune condiţia de a nu părăsi tabloul, lucru care îl
vom respecta testând coordonatele noului punct să aparţină mulţimii [1..nrlinii] şi [1..nrcol].
Săritura calului. Fiind dată o tablă de şah de dimensiunea nxn şi un cal în colţul stânga sus al
acesteia, se cere să se afişeze toate posibilităţile de mutare a acestei piese de şah astfel încât să
treacă o singură dată prin fiecare pătrat al tablei. O soluţie va fi afişată ca o matrice nxn în care sunt
numerotate săriturile calului.
Exemplu, pentru n=5, o soluţie este
1 14 9 20 23
10 19 22 15 8
5 2 13 24 21
18 11 4 7 16
3 6 17 12 25
Pentru rezolvarea acestei probleme vom codifica direcţiile de deplasare pentru că ar fi ineficient să
scriem două cicluri for de la –2 la 2 cu cele 25 de variante de deplasare din care valide sunt doar
opt. De asemenea aici spre deosebire de celelalte probleme tratate la aplicarea metodei
backtracking în plan nu vom folosi un vector soluţie, ci vom scrie săriturile în tablou urmărind ca
la revenire să refacem poziţiile ocupate pentru a nu se lua blocaje. În figura de mai jos sunt
prezentate cele 8 mutări posibile pentru un cal.
Varianta C/C++
Varianta Pascal
const dx:array[1..8] of -2..2=(-1,1,2,2,1,-1,- #include<fstream.h>
2,-2); const int dx[8]={-1,1,2,2,1,-1,-2,-2};
dy:array[1..8] of -2..2=(-2,-2,-1,1,2,2,1,-1); const int dy[8]={-2,-2,-1,1,2,2,1,-1};
var a:array[1..10,1..10] of integer; int a[10][10],n;
n:integer; ofstream f("cal.out");
f:text; void afis()
procedure cit; { int i,j;
var i,j :integer; for(i=1;i<=n;i++)
begin { for(j=1;j<=n;j++) f<<a[i][j]<<" ";
readln(n); f<<endl;
for i:=1 to n do }
for j:=1 to n do a[i,j]:=0; f<<endl;
end; }
procedure afis; int inside(int i,int j)
var i,j:integer; {
begin return i>=1 && i<=n && j>=1 && j<=n;
for i:=1 to n do begin }
for j:=1 to n do write(f,a[i,j]:3); void back(int i, int j, int pas)
writeln(f); { int k,inou,jnou;
end; a[i][j]=pas;
writeln(f); if (pas==n*n) afis();
end; else for(k=0;k<8;k++)
FUNCTION inside (i,j:integer):boolean; { inou=i+dx[k];
begin jnou=j+dy[k];
inside:=(i in [1..n])and (j in [1..n]) if (inside(inou,jnou) && a[inou][jnou]==0)
end; back(inou,jnou,pas+1);
procedure back(i,j,pas:integer); }
var k,inou,jnou:integer; a[i][j]=0;
begin }
a[i,j]:=pas; void main()
if pas=n*n then afis { cin>>n;;
else for k:=1 to 8 do begin back(1,1,1);
inou:=i+dx[k]; }
jnou:=j+dy[k];
if inside(inou,jnou) and (a[inou,jnou]=0)
then back(inou,jnou,pas+1);
end;
a[i,j]:=0;
end;
begin
assign(f,'cal.txt');
rewrite(f);
cit;
back(1,1,1);
close(f);
end.
La aceste categorii de probleme se adaugă şi cele de optim, care presupun alegerea soluţiei optime
dintre cele generate.
De asemenea, problemele de combinatorică se pot rezolva folosind metoda backtracking. Soluţiile
cerute se pot reprezenta ca vectori de forma X = (x1, ..., xn)ÎS unde S = S1 x ... x Sn, unde
mulţimile S1, ...,Sn sunt mulţimi finite. Soluţiile se generează element cu element şi trebuie să
respecte o serie de reguli, în funcţie de problema de generare concretă.
Algoritmii de tip backtracking prezentaţi în capitolul anterior vor fi folosiţi pentru a genera
permutări, aranjamente, etc. Pentru fiecare probleme, însă, putem face modificări pentru a creşte
eficienţa algoritmului de rezolvare sau pentru a-l simplifica. Pentru fiecare algoritm vom identifica
particularităţile sale şi condiţiile care trebuie puse asupra vectorului soluţie.
Algoritmii şi programele prezentate mai jos folosesc mulţimi de forma {1,2,…,n} pentru a
simplifica lucrurile. Trecerea la o mulţime generală se face setul de simplu deoarece generând
indicii, practic se generează mulţimea, şi astfel, oricărui vector soluţie X generat pe baza indicilor i
se poate asocia o soluţie dintr-o mulţime oarecare.
De asemenea, este bine să numărăm câte soluţii generează fiecare program şi să verificăm aceste
numere cu ajutorul formulelor cunoscute de la matematică.
Generarea permutărilor
Se dă o mulţime cu n elemente A={a1,a2,…,an}. Se cere să se genereze si să se afişeze toate
permutările ei. Altfel spus, se cere să se afişeze toate modurile în care se pot amesteca elementele
mulţimii A.
Folosim pentru generare mulţimea {1,2,…,n}. Condiţiile care se pun sunt următoarele:
• Fiecare element din vectorul X se ia din {1,2,…,n};
• Un element Xk este valid dacă el nu a fost plasat anterior în vectorul soluţie X;
• Când am generat n elemente cu condiţiile de mai sus, atunci avem o soluţie.
Se pot identifica mai multe modalităţi de a verifica dacă elementul Xk a fost plasat deja în vectorul
soluţie. Cele mai importante două sunt:
• parcurgerea elementelor deja generate pentru a verifica daca Xk apare sau nu între ele;
• folosirea unui vector cu n elemente în care vom avea valori 0 sau 1 corespunzătoare
elementelor mulţimii iniţiale. Valoarea 1 va preciza faptul că elementul de pe poziţia
corespunzătoare a fost plasat anterior în vectorul soluţie, iar valoarea 0 că nu.
Corespunzător acestor două moduri de a verifica dacă un element a mai fost sau nu plasat în
vectorul soluţie, avem 2 moduri de generare a permutărilor.
Generarea aranjamentelor
Generăm aranjamentele unei mulţimi atunci când ne se cer toate modurile de a alege m elemente
distincte dintre cele n ale mulţimii (m<n).
Această problemă se rezolvă foarte uşor folosind metodele de generarea permutărilor. Singurele
modificări presupun citirea numărului m, modificarea condiţiei de soluţie, care va fi k=m în loc de
k=n şi a numărului de elemente afişate.
Generarea combinărilor
Generăm combinărilor unei mulţimi presupune o condiţie suplimentară faţă de permutări sau
aranjamente. Acest lucru se datorează faptului că generarea combinărilor presupune alegerea în
ordine strict crescătoare a elementelor care compun vectorul soluţie.
Astfel, condiţia de continuare, sau de validare a unui element este aceea că el trebuie să fie strict
mai mare decât cel plasat anterior. În acest mod asigurăm faptul că elementele nu se vor repeta şi
că vor fi generate în ordine strict crescătoare. Trebuie, însă, să avem grijă să nu punem această
condiţie si asupra primului element din vectorul soluţie, deoarece el nu are cu cine să fie comparat.