Sunteți pe pagina 1din 17

Introducere …………………………………………………………………… 2

I. Metoda de programare Backtracking ……...………………………………. 3


II. Metoda Backtracking generalizat ……….….…….…….…………………. 5
III. Problema Labirintului …………………………………………………… 7
IV. Problema sariturii calului ……………………………………… 11
V. Problema Bilei …………………………………………………. 13
VI. Backtracking generalizat recursiv ..……....……………………. 15
VII. Problema labirintului (recursiv) ……………...……………….. 16
Bibliografie ………………………………………………………… 17

3
Pentru prelucrarea informaţiei omul a inventat calculatorul, dar datoritǎ dezvoltǎrii
vertiginoase a prelucrǎrilor de date cu calculatorul, s-au putut aborda şi rezolva probleme
din ce în ce mai complexe.
Definit în anul 1971 de cǎtre Niklaus Wirth, limbajul Pascal (numit astfel în cinstea
matematicianului francez Blaise Pascal), este un limbaj de interes general, coceput iniţial
în scop didactic, ca instrument de învǎţare a programǎrii în mod sistematic. Datoritǎ
calitǎţilor sale (foloseşte un mod bine structurat de reprezentare a programelor, asigurǎ
claritate, sugestivitate şi simplitate), acest limbaj a fost adoptat rapid ca limbaj de iniţiere
în programare şi a fost apoi axtins cu facilitǎţi care sǎ-i asigure utilizarea performantǎ ca
limbaj înalt ce poate fi folosit în rezolvarea unei mari diversitǎţi de probleme, cu grad
sporit de complexitate.
Limbajul de programare PASCAL este un limbaj agreat de programatori,
permiţându-le acestora sǎ alcǎtuiascǎ cu uşurinţǎ în mod sistematic programe complexe.
Lucrarea urmǎreşte prezentarea şi explicarea detaliatǎ a metodei
BACKTRACKING punând accent pe forma generalizatǎ a metodei. Aceasta cuprinde, pe
lângǎ toate toate aspectele usual abordate în cadrul metodei, şi unele chestiuni de
dificultate sporitǎ, oferind astfel puncte de pornire în aprofundarea metodei.
În capitolele I şi II, pentru fixarea cunoştinţelor de bazǎ şi pentru crearea unor
deprinderi de organizare riguroasǎ în cadrul metodei Backtracking simple şi generalizate.
S-au inclus în capitolele III, IV şi V probleme ce se rezolvǎ cu ajutorul metodei,
toate fiind însoţite de explicarea şi rezolvarea completǎ, dând şi indicaţii despre
particularitǎţi ale metodei. Problemele nu sunt de acelaşi nivel, dificultatea acestora
crescând pe parcursul celor 3 capitole.
Facem referire cǎ problemele rezolvate sub formǎ de program în limbaj de
programare Borland Pascal au fost mai întâi testate şi verificate pentru evitarea
erorilor.
Capitolul VI exemplificǎ utilizarea metodei Backtracking generalizat recursive, dǎ
detalii în legǎturǎ cu modul acesta de rezolvare a problemelor, în capitolul VII fiind
reluatǎ problema din capitolul III dar implementatǎ acum recursiv.

4
De multe ori, în aplicaţii apar probleme în care se cere gǎsirea unor soluţii de forma
x=x1x2... xn unde xi  A, i = 1,…,n în care x1…xn trebuie sǎ îndeplineascǎ anumite condiţii.
Am putea sǎ generǎm toate combinaţiile posibile de valori şi apoi sǎ le alegem doar pe cele
convenabile. Considerând mulţimile A = {ai,1,ai,2,…,ai,n(i)}, aceste combinaţii s-ar putea construi
astfel: pentru fiecare valoare posibilǎ fixatǎ pentru componenta xi, vom alege toate valorile
posibile pentru componenta xi+1 şi pentru fiecare astfel de valoare fixatǎ pentru xi+1 vom alege
toate valorile posibile pentru componenta xi+2, etc.
Rezolvând problema în acest mod, deci generînd tote elementele produsului cartezian
A1  A2  ...  An şi verificând abia apoi dacǎ fiecare combinaţie este o soluţie, eficientǎ este
scǎzutǎ.
Astfel, dacǎ de exemplu ne propunem sǎ generǎm toate cuvintele formate cu litere a,b,c,
aşa încât fiecare literǎ sǎ aparǎ o singurǎ datǎ, combinaţiile posibile sunt în numǎr de 27, dintre
care convin doar 6.
Tehnica Backtracking propune generarea soluţiei prin completarea vectorului x în ordine
x1x2... xn şi are la bazǎ un principiu “de bun simţ”: dacǎ se constatǎ cǎ având o combinaţie parţialǎ
de formǎ v1v2...v k-1 (unde vi,…,vk-1 sunt valori deja fixate), dacǎ alegem pentru xk o valoare vk şi
combinaţia rezultatǎ nu ne permite sǎ ajungem la o soluţie, se renunţǎ la aceastǎ valoare şi se
încearcǎ o alta (dintre cele netestate în aceastǎ etapǎ). Într-adevǎr, oricum am alega celelalte
valori, dacǎ una nu corespunde nu putem avea o soluţie.
Pentru exemplu ales anterior se observǎ cǎ dacǎ notǎm cuvântul cu x1x2x3, combinaţia aax3
nu ne poate conduce la o soluţie (literele trebuie sǎ fie distincte) şi deci nu are sens sǎ mai
încercǎm sǎ stabilim valori pentru x3.

Altgoritmul general al metodei Backtracking


Pentru evitarea generǎrii combinaţiilor neconvenabile se procedeazǎ astfel:
Presupunem cǎ s-au gǎsit valorile v1v2…vk-1 pentru componentele x1x2... xk-1 (au rǎmas de
determinat valorile pentru xk…xn). ne ocupǎm în continuare de componenta xk. Paşii urmaţi sunt:
1. Pentru început, pentru xk nu s-a testat încǎ nici o valoare.
2. Se verificǎ dacǎ existǎ valori netestate pentru xk .
a) În caz afirmativ, se trece la pasul 3.
b) Altfel, se revine la componenta anterioarǎ, xk-1; se reia pasul 2 pentru k=k-1.
3. Se alege prima valoare v dintre cele netestate încǎ pentru xk.
4. Se verificǎ dacǎ acestǎ combinaţie parţialǎ v1v2…vk-1v ne poate conduce la un rezultat
(dacǎ sunt îndeplinite anumite condiţii de continuare).
a) Dacǎ valoarea aleasǎ este bunǎ se trece la pasul 5.
b) Altfel, se rǎmâne pe aceeaşi poziţie k şi se reia cazul 2.
5. Se verificǎ dacǎ s-a obţinut o soluţie .
a) În caz afirmativ, se tipǎreşte aceastǎ soluţie şi se rǎmâne la aceeaşi componentǎ
xk, reluându-se pasul 2.
b) Altfel se reia altgoritmul pentru urmǎtoarea componentǎ (se trece la pasul 1
pentru k=k+1).
5
Altgoritmul începe prin stabilirea unei valori pentru componenta x1(k=1) şi se încheie când
pentru aceasta am testat toate valorile posibile şi conform pasului 2b) ar trebui sǎ revenim la
componenta anterioarǎ, care în aceast caz nu existǎ.
Rezumând, metoda Backtracking se foloseşte în rezolvarea problemelor care îndeplinesc
condiţiile:
- soluţia poate fi pusǎ sub forma unui vector S=x1x2…xn, unde xi  Ai , i  1,..., n;
- mulţimile Ai sunt finite şi ordonate (pentru a lua în considerare toate valorile posibile).

☺Observaţii: - în unele probleme n variazǎ de la o soluţie la


alta;
mulţimile Ai pot coincide;
metoda Backtracking oferǎ toate soluţiile.
Înainte de a scrie programul care ne va obţine soluţiile, trebuie sǎ stabilim unele detalii cu
privire la:
- vectorul soluţie – câte componente are, ce menţine fiecare componentǎ.
- mulţimea de valori posibile pentru fiecare componentǎ (sunt foarte importante
limitele acestei mulţimi).
- condiţiile de continuare (condiţiile ca o valoare x[k]sǎ fie acceptatǎ).
- condiţia ca ansamblul de valori generat sǎ fie soluţie.

Pe baza acestor date vom scrie apoi procedurile şi funcţiile pe care le vom apela în
altgoritmul general al metodei, dat mai jos, care se poate aplica tuturor problemelor ce respectǎ
condiţiile menţionate anterior. Aceste proceduri şi funcţii au o semnificaţie comunǎ, prezentând
însǎ particularitǎţi în funcţie de fiecare problemǎ în parte.
Astfel, se va nota cu x vectorul care conţine soluţia; x[k] = v va avea ca semnificaţie
faptul cǎ elementul al-v-lea din mulţimea de valori ppsibile Ak a fost selectat pentru componenta
xk. dacǎ mulţimea Ak are m elemente, a1a2…am,pentru uşurinţǎ ne vom referii la indicii lor 1,2,
…,m. Deci valorile posibile pentru o componentǎ vor fi 1,2,…,m în aceastǎ ordine.
Iniţial, când pentru o componentǎ nu am testat încǎ nimic, aceasta va avea valoarea 0 (un
indice care nu existǎ). Aceastǎ operaţie se va realiza în procedura INIT care va avea ce
parametru poziţia k.

☺Observaţie: De obicei valorile posibile sunt chiar successive şi în acest caz se poate
considera cǎ x[k] = v are semnificaţia cǎ pentru componenta xk s-a ales chiar
valoarea v. În acest caz iniţializarea trebuie fǎcutǎ cu o valoare imediat înaintea
primei valori posibile. De exemplu dacǎ valorile posibile ar fi 5,6,7,… atunci
iniţializarea se va face cu valoarea x[k] = 4
Funcţia EXISTA(k) verificǎ dacǎ ultima valoare aleasǎ pentru componenta xk nu a atins
limita maximǎ admisǎ (indicele de valoare maximǎ). Întrucât elementele sunt testate în ordine,
acest lucru este echivalent cu a verifica dacǎ mai avem valori netestate încǎ pentru aceastǎ
componentǎ.
Funcţia CONT(k) verificǎ dacǎ valoarea aleasǎ pentru x[k] îndeplineşte condiţiile de
continuare, deci dacǎ aceastǎ combinaţie parţialǎ v1v2…vk poate sǎ conducǎ la o soluţie.
☺Observaţie: La implementarea acestei funcţii, de obicei se porneşte de la premisa cǎ
se Funcţia
poate obţine o soluţie şi verificǎ
SOLUTIE(k) se identificǎ
dacǎ acele cazuri
s-a ajuns la oînsoluţie
care acest lucru este posibil.
finalǎ.
Procedura TIPAR(k) tipǎreşte o soluţie.

6
Altgoritmul propus este:
procedure BKT;
var k:integer;
begin
k:=1;
INIT(k);
while k>0 do
if EXISTA(k) then
begin
x[k]:=x[k]+1;
VALPOS(k);
if CONT(k) then
if SOLUTIE(k) then
TIPAR(k)
else
begin
k:=k+1;
INIT(k);
end;
end
else
k:=k-1;
end;

☺Observaţii: În situaţiile în care operaţiile relizate în procedurile enunţate


sunt simple, se poate renunţa la implementarea lor în aceastǎ formǎ, iar
altgoritmul general va conţine direct aceste operaţii.

De asemenea, trebuie sǎ avem în vedere cǎ altgoritmul general se poate modifica şi adapta


în funcţie de problema rezolvatǎ.

Metoda Backtracking generalizat are urmǎtoarea deosebire faţǎ de metoda obişnuitǎ de


Backtracking: în metoda obişnuitǎ vectorul soluţie este un tablou unidimensional, x 1,x2…xn,
fiecare componentǎ având o anumitǎ valoare la un moment dat, dar dacǎ componenta x k are mai
multe caracteristici atunci este nevoie folosirea metodei generalizate.
În acest caz vectorul x trebuie sǎ descrie aceste caracteristici. Valorile posibile ale unei
componente trebuie generate în ordine, dar pentru cǎ o valoare are mai multe caracteristici vom
utiliza o variabilǎ auxiliarǎ cu ajutorul cǎreia vom nota (şi vom obţine) în ordine toate aceste
valori posibile.

7
Astfel, pentru a genera toate valorile posibile pentru o componentǎ k este suficient sǎ
generǎm toate valorile posibile pentru aceastǎ variabilǎ auxiliarǎ şi pe baza lor sǎ aflǎm valorile
lui x[k].
De exemplu dacǎ x este vectorul soluţie, iar d vectorul auxiliar, putem descrie un tip de
bazǎ pentru o componentǎ astfel:

const nmax=20 ;
type component=record
caract1: tip1;
caract2: tip2;
…………
end;
var x:array[1..nmax] of component;
d:array[1..nmax] of integer;

Un altgoritm general ar putea fi:


procedure BKTG;
var k:integer;
begin
k:=1;
INIT(k);
while k>0 do
if EXISTA(k) then
begin
d[k]:=d[k]+1;
VALPOS(k);
if CONT(k) then
if SOLUTIE(k) then
TIPAR(k)
else
begin
k:=k+1;
INIT(k);
end;
end
else
k:=k-1;
end;

Procedura INIT va iniţializa datele referitoare la componenta k-practic va iniţializa


componenta corespunzǎtoare din vectorul auxiliar, d[k].
Funcţia EXISTA verificǎ dacǎ mai existǎ valori netestate încǎ pentru componenta k
(practic dacǎ mai existǎ valori posibile pentru componenta corespunzatoare din vectorul auxiliar).
Procedura VALPOS va completa pentru componenta k în vectorul soluţie valoarea
caracteristicilor sale, în funcţie de valoarea lui d[k].
CONT, SOLUTIE, TIPAR au aceeaşi semnificaţie ca şi în cazul metodei simple.

☺Observaţie: Uneori este posibil ca prima componenetǎ (sau primele) sǎ aibǎ valori
deja fixate şi în acest caz generarea se realizeazǎ pentru componentele 2,3, …

8
Se dǎ un labirint sub formǎ de
matrice
cu m linii si n coloane. Fiecare element al
matricei se codificǎ cu: ‘0’ dacǎ este zid şi
cu ‘1’ dacǎ este culoar.

Într-un punct al labirintului, de coordonate


(l0,c0) se gǎseşte o persoanǎ. Se cere sǎ se
gǎseascǎ toate ieşirile din labirint.
De exemplu, pentru un labirint cu configuraţia

0 0 1 0 0
0 0 1 0 0
1 1 1 1 1
0 0 0 1 1
0 0 0 0 0
unde l0=3, c0=3,
am putea avea posibilitǎţile:
0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0
0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 1 1 0 0 0 1 1 0 0 0 1 1 0 0 0 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Pentru a scrie programul stabilim urmǎtoarele:
- vom folosi matricea tab pentru a memora configuraţia labirintului.
- vectorul soluţie are un numǎr variabil de componente şi conţine o succesiune de
elemente ale tabloului care ar reprezenta un drum în labirint. Un element al vectorului,
x[k], conţine coordonatele unui punct în care ne aflǎm la pasul respective: linia si
coloana (l,c).
- pentru a determina mulţimea de valori posibile pentru o componentǎ, ţinem cont de
urmǎtoarele:
Aflându-se într-un punct dat, persoana poate sǎ mearga în 4 direcţii pe care le codificǎm cu
1,2,3,4
Fiecare direcţie de deplasare induce un anumit deplasament liniei, respectiv coloanei.
Astfel:
j - pe direcţia 1: linia scade cu o unitate, deci deplasamentul ei este –1
coloana rǎmâne aceeşi, deci deplasamentul ei este 0
1 - pe direcţia 2: linia rǎmâne aceeaşi, deci deplasamentul ei este 0
9
i 3 * 2 coloana creşte cu o unitate, deci deplasamentul ei este 1
4 - pe direcţia 3: linia creşte cu o unitate, deci deplasamentul ei este 1
coloana rǎmâne aceeşi, deci deplasamentul ei este 0
- pe direcţia 4: linia rǎmâne aceeaşi, deci deplasamentul ei este 0
coloana scade cu o unitate, deci deplasamentul ei este -1

Din punctul k-1 caracterizat de coordonatele (x[k-1].1,x[k-1].c) ca punct urmǎtor


în traseul urmat ar putea fi unul din punctele vecine date de direcţia de deplasare aleasǎ. Deci
vom alege ca vector auxiliar un vector d care ne memoreazǎ direcţia aleasǎ pentru a ajunge în
punctul curent.
Astel, coordonatele punctului curent se deduc în funcţie de punctul din care se pleacǎ,
x[k-1], direcţia de deplasare aleasǎ, d[k], respectiv deplasamentul indus de aceastǎ direcţie
liniei si coloanei:

X[k].l = x[k-1].l + depl[d[k]].l


X[k].c = x[k-1].c + depl[d[k]].c

Deplasamentele fiind nişte mǎrimi constante, pot fi initializate de la declarare.


Procedura VALPOS calculeazǎ coordonatele punctului corespunzǎtor componentei k în
funcţie de punctul din care se porneşte şi de direcţia aleasǎ.
- condiţii de continuare pentru ca o valoare x[k] sǎ fie acceptatǎ:
- persoana nu trebuie sǎ treacǎ de 2 ori prin acelaşi loc;
- valoarea x[k] trebuie sǎ corespundǎ unui culoar.
- am gǎsit o soluţie finalǎ dacǎ am ajuns pe una din laturile labirintului, deci linia sau
coloana sǎ se afle pe una din margini.
Pentru exemplu considerat, vectorul soluţie se va completa astfel:

d1d2d3… x1 x 2 x 3 …
0 (3,3) Stabilim valoarea primei componente, care este corespunzǎtoare
punctului din care se pleacǎ(l0,c0). Direcţia din care s-a ajuns aici
nu intereseazǎ.
01 (3,3)(2,3) Prima direcţie posibilǎ este 1. Din (3,3) pe directia 1 ajungem in
punctul (2,3) -convine este pe culoar. Trecem la urmǎtoarea
componentǎ, k=3.
011 (3,3)(2,3)(1,3) Începem cu prima direcţie posibilǎ pentru acestǎ componentǎ,
d[3]=1; coordonatele punctului corespunzǎtor lui k=3 în care
ajungem din x[2]pe direcţia 1 sunt (1,3) -convine. Se observǎ cǎ
am ajuns la marginea labirintului, deci am obţinut o soluţie ,pe care
o tipǎrim. Rǎmânem la k=3.
012 (3,3)(2,3)(2,4) Urmǎtoarea valoare posibilǎ pentru d[3] este 2; punctul în care
ajungem este (2,4) care nu convine, fiind în zid. Rǎmânem la k=3.
013 (3,3)(2,3)(3,3) Pornind din (2,3) pe direcţia 3 ajungem în (3,3)- nu convine, am
mai trecut pe aici. Deci in continuare k=3.
014 (3,3)(2,3)(2,2) Pentru urmǎtoarea direcţie, 4, punctul în care se ajunge din (2,3)
este (2,2) –nu convine este zid. Am epuizat toate direcţiile posibile
pentru k=3, deci revenim la k=2.
02 (3,3)(3,4) Urmǎtoarea direcţie posibilǎ pentru k=2 este 2; punctul în care se
ajunge este (3,4), care convine. Trecem la k=3;
021 (3,3)(3,4)(2,4) Prima direcţie aleasa este 1; pornind din x[k-1] –punctul (3,4),
10
ajungem în (2,4) – nu convine, fiind zid, rǎmânem la k=3;
022 (3,3)(3,4)(3,5) Pe direcţia d[3]=2, punctul în care se ajunge este (3,5) –este pe
margine, deci am obţinut o nouǎ soluţie. Rǎmânem la k=3, pentru o
nouǎ direcţie.
023 (3,3)(3,4)(4,4) Urmǎtoarea valoare pentru d[3]este 3, iar x[3]-punctul (4,4) –
convine; trecem la k=4.
0231 (3,3)(3,4)(3,4) Prima direcţie posibilǎ este d[4]=1, iar x[4]este punctul (3,4) –
nu convine; rǎmânem la k=4.
… Procedeul continuǎ pânǎ când am epuizat toate valorile posibile
pentru componenta d[2](de la ea începe generarea).
Procedura BKTG este modificatǎ în ceea ce priveste faptul cǎ generarea se face pentru
componentele 2,3,… deoarece prima poziţie este fixatǎ.
Programul corespunzǎtor este:

program labirint1;
uses crt;
type component=record
l,c:integer;
end;
vectsol=array[1..100]of component;
auxiliar=array[1..100]of 0..4;
labirint=array[1..25,1..25]of char;
const depl:array[1..4]of component=((l:-1;c:0),(l:0;c:1), (l:1;c:0),
(l:0;c:-1));

var x:vectsol;
d:auxiliar;
tab:labirint;
n,m:integer;
l0,c0:integer;

procedure citire;
var i,j:integer;
begin
clrscr;
writeln('configuratia labirintului: ');
write('m=');readln(m);
write('n=');readln(n);
writeln('Se codifica astfel: 1-culoar; 0-zid');
for i:=1 to m do
for j:=1 to n do
begin
write('tab[',i,',',j,']=');
readln(tab[i,j]);
end;
writeln('Pozitia initiala: ');
write('l0=');readln(l0);
write('c0=');readln(c0);
x[1].l:=l0;
x[1].c:=c0;
end;

procedure INIT(k:integer);
begin
d[k]:=0;
end;

11
function EXISTA(k:integer):boolean;
begin
EXISTA:=d[k]<4;
end;
procedure VALPOS(k:integer);
begin
x[k].l:=x[k-1].l+depl[d[k]].l;
x[k].c:=x[k-1].c+depl[d[k]].c;
end;

function CONT(k:integer):boolean;
var i:integer;
begin
CONT:=true;
for i:=1 to k-1 do
if(x[i].l=x[k].l)and(x[i].c=x[k].c)then
CONT:=false;
with x[k] do
if tab[l,c]='0'then
CONT:=false;
end;

function SOLUTIE(k:integer):boolean;
begin
with x[k] do
SOLUTIE:= (l=1)or(c=1)or(l=m)or(c=n)
end;

procedure TIPAR(k:integer);
var i,j:integer;
begin
for i:=1 to k do
with x[i] do
write(l,' ',c, ' ');
readln;
end;

procedure BKTG;
var k:integer;
begin
k:=2;
INIT(k);
while k>1 do
if EXISTA(k)then
begin
d[k]:=d[k]+1;
VALPOS(k);
if CONT(k)then
if SOLUTIE(k)then
TIPAR(k)
else
begin
k:=k+1;
INIT(k);
end;
end
else
k:=k-1;
end;
12
begin
CITIRE;
BKTG;
end.

Se dǎ o tablǎ de şah de dimensiune mxn. Un cal se aflǎ


în poziţia (l0,c0). Sǎ se gǎseascǎ toate modalitǎţile prin care
acesta poate sǎ parcurgǎ întreaga tablǎ farǎ sǎ treacǎ de
douǎ ori prin acelaşi loc.

De exemplu, pentru n = m = 5, şi poziţia iniţialǎ (1,1) o soluţie este:

1 20 17 12 3
16 11 2 7 18
21 24 19 4 13
10 15 6 23 8
25 22 9 14 5

Problema trateazǎ aceeaşi situaţie ca şi în cazul labirintului, având specificǎ alegerea


valorilor posibile pentru o componentǎ.

Pentru a scrie programul, vom stabili urmǎtoarele repere:


- vectorul solutie are nxm componente, fiind nxm elemente pe tabla de 8 1
şah (iar calul trebuie sǎ treacǎ prin toate). Fiecare componentǎ caracterizeazǎ 7 2
un element al tablei prin coordonatele sale l,c; *
- determinarea valorilor posibile pentru componenta k se face astfel: 6 3
aflându-se într-un punct dat, calul poate sǎri în 8 direcţii pe care le codificǎm 5 4
1,2, …, 8, ca în figura alǎturatǎ.
- pe direcţia 1: calul se mutǎ cu 2 linii mai sus, deci deplasamentul liniei este –2
coloana se mutǎ la dreapta cu 1, deci deplasamentul ei este 1
- pe direcţia 2: linia scade cu 1, deci deplasamentul ei este -1
coloana creşte cu 2 unitaţi, deci deplasamentul ei este 2
- pe direcţia 3: linia coboarǎ cu o unitate, deci deplasamentul ei este -1
coloana se mutǎ la dreapta cu 2, deci deplasamentul ei este 2
………………………
(analog se completeazǎ deplasamentele pentru toate cele 8 cazuri).
Din punctual k-1,caracterizat de coordonatele (x[k-1].l,x[k-1].c), ca punct
urmǎtor în traseul urmat ar putea fi unul din punctele date de direcţia de deplasare aleasǎ. Deci
vom alege ca vector auxiliar un vector d care ne memoreazǎ direcţia aleasǎ pentru a ajunge în
punctul current.
Astfel, coordonatele punctului curent se deduc în funcţie de punctul din care se pleacǎ,
x[k-1], direcţia de deplasare aleasǎ, d[k],respective deplasamentul Indus de aceastǎ direcţie
liniei şi coloanei:
X[k].l = x[k-1].l + depl[d[k]].l

13
X[k].c = x[k-1].c + depl[d[k]].c
Deplasamentele fiind nişte mǎrimi constante, pot fi iniţializate de la declarare.
- condiţii de continuare:
- poziţia aleasǎ nu trebuie sǎ fie în afara tablei de şah;
- calul nu trebuie sǎ trecǎ de mai multe ori prin acelaşi loc, deci x[k]≠x[i]
pentru orice i=1, …,k-1;
- am am gǎsit o soluţie finalǎ dacǎ am completat toate componentele vectorului (deci
k=nxm ).
Pentru exemplul considerat se va stabili prima componentǎ cu coordonatele punctului în
care se aflǎ persoana iniţial: k =1, x[k].l = l0 =1, x[k].c = c0 = 1.
Se începe de la k = 2. Vectorul soluţie se va completa astfel:

d1d2d3… x1 x2 x3 …
0 (1,1) Stabilim valoarea primei componente, care este
corespunzǎtoare punctului de plecare (l0,c0).
Direcţia din care a ajuns aici nu ne intereseazǎ.
01 (1,1)(-1,2) Prima direcţie posibilǎ este 1. din (1,1) pe direcţia 1
ieşim de pe tabla de şah, deci nu convine; rǎmânem
la k=2.
02 (1.1)(0,3) Pe aceastǎ direcţie de asemenea pǎrǎsim tabla, deci
rǎmânem la k=2.
03 (1,1)(2,3) Pentru aceastǎ direcţie ajungem în (2,3)
-convine,deci trecem la k=3.
031 (1,1)(2,3)(0,4) Testǎm prima direcţie posibilǎ: pornind din (2,3) pe
direcţia 1 ajungem în (0,4) – nu convine, am ieşit
de pe tablǎ. Deci în continuare k=3.
032 (1,1)(2,3)(1,5) Pentru urmǎtoarea direcţie, 2, punctual în care se
ajunge din (2,3)este (1,5) –convine, deci trecem la
k=4.
… Procedeul continuǎ pânǎ când am epuizat toate
valorile pentru componenta d[2] (de la ea începe
generarea).
Datele folosite în program sunt:
type component=record
l,c:integer;
end;
vectsol=array[1..100]of component;
auxiliar=array[1..100]of 0..4;
tabla=array[1..25,1..25]of integer;
const depl:array[1..8]of component=((l:-2;c:1),(l:-1;c:2),(l:1;c:2),
(l:2;c:1),(l:2;c:-1),(l:1;c:-2),(l:-1;c:-2),(l:-2;c:-1));
var x:vectsol;
d:auxiliar;
n,m:integer;
l0,c0:integer;

Procedurile şi funcţiile care prezintǎ particularitǎţi sunt:


procedure citire;
var i,j:integer;
begin
14
write('m=');readln(m);
write('n=');readln(n);
writeln('Pozitia initiala: ');
write('l0=');readln(l0);
write('c0=');readln(c0);
x[1].l:=l0;
x[1].c:=c0;
end;

function EXISTA(k:integer):boolean;
begin
EXISTA:=d[k]<=8;
end;

function CONT(k:integer):boolean;
var i:integer;
begin
CONT:=true;
with x[k] do
if (l<1)or(c<1)or(l>m)or(c>n)then
CONT:=false;
for i:=1 to k-1 do
if(x[i].l=x[k].l)and(x[i].c=x[k].c)then
CONT:=false;
end;

function SOLUTIE(k:integer):boolean;
begin
SOLUTIE:=(k=m*n);
end;

Se dǎ un teren parcelat în care se cunoaşte înǎlţimea


fiecǎrei porţiuni de teren. O bilǎ se aflǎ în parcela (l0,c0).
Sǎ se gǎseascǎ toate modalitǎţile prin care bila
poate ajunge la marginea terenului ştiind cǎ ea poate trece
doar într-o parcelǎ vecinǎ de înǎltime mai micǎ.
Configuraţia terenului poate fi memoratǎ sub forma
unei matrici, un element al matricii corespunzând unei
parcele.

Pentru a scrie programul, vom stabili urmǎtoarele repere:


- vectorul soluţie are un numǎr variabil de componente şi menţine în ordine parcelele prin
care trece bila.
- valorile posibile se determinǎ ţinând cont cǎ, dintr-un punct dat, bila poate sǎ meargǎ în 8
direcţii pe care le codificǎm cu 1,2, …, 8; fiecare direcţie de deplasare induce un anumit
deplasament linie, respective coloanei; astfel:
j 6 5 4

8 1 2 - direcţia 1: bila se mutǎ cu 1 linie mai sus, deci deplasamentul liniei este –
i 7 * 3 1 coloana rǎmâne neschimbatǎ, deci deplasamentul ei este 0
15
- pe direcţia 2: liniei este –1 coloana se mutǎ la dreapta cu 1, deci deplasamentul ei este
bila se mutǎ cu 1
1 linie mai sus, - pe direcţia 3: bila rǎmâne pe aceeaşi linie , deci deplasamentul liniei este
deci 0 coloana se mutǎ la dreapta cu 1, deci deplasamentul ei este 1
deplasamentul ……………
(analog se completeazǎ deplasamentele pentru toate cele 8 cazuri).
Din punctual k-1, caracterizat de coordonatele (x[k-1].l,x[k-1].c), ca punct
urmǎtor în traseu ar putea fi unul din punctele vecine date de direcţia de deplasare aleasǎ. Deci
vom alege ca vector auxiliar un vector d care ne memorezǎ direcţia aleasǎ pentru a ajunge în
punctual current.
- condiţii de continuare pentru ca o valoare x[k]sǎ fie acceptatǎ: bila nu poate trece decât
pe o pozitie vecinǎ cu înǎlţimea mai mica;
- am gǎsit o soluţie finalǎ dacǎ am ajuns la marginea terenului.
Declaraţiile folosite în program sunt:
type component=record
l,c:integer;
end;
vectsol=array[1..100]of component;
auxiliar=array[1..100]of 0..4;
teren=array[1..25,1..25]of integer;
const depl:array[1..8]of component=((l:1;c:-1),(l:-1;c:1),(l:0;c:1),
(l:1;c:1),(l:1;c:0),(l:1;c:-1),(l:0;c:-1),(l:-1;c:-1));
var x:vectsol;
d:auxiliar;
n,m:integer;
l0,c0:integer;
cote:teren;

Procedurile şi funcţiile care prezintǎ particularitǎţi sunt:


procedure citire;
var i,j:integer;
begin
writeln('configuratia terenului:');
write('m=');readln(m);
write('n=');readln(n);
for i:=1 to m do
for j:=1 to n do
begin
write('cote[',i,',',j,']=');
readln(cote[i,j]);
end;
writeln('Pozitia initiala: ');
write('l0=');readln(l0);
write('c0=');readln(c0);
x[1].l:=l0;
x[1].c:=c0;
end;

function EXISTA(k:integer):boolean;
begin
EXISTA:=d[k]<=8;
end;

function CONT(k:integer):boolean;
var i:integer;
begin
with x[k] do CONT:=cote[x[k-1].l,x[k-1].c]>cote[l,c];
16
end;

function SOLUTIE(k:integer):boolean;
begin
with x[k] do SOLUTIE:=(l=1)or(c=1)or(l=m)or(c=n);
end;

Dacǎ am scrie un altgoritm care operaţiile efectuate asupra unei componente (fie ea k) a
vectorului soluţie generat prin metoda Backtracking generalizat, atunci am putea apela acest
altgoritm şi pentru componenta urmatoare, k+1 (pentru cǎ acţiunile realizate asupra acestei
componente sunt similare, însǎ aplicate altor valori). Dar cum trecerea de la componenta k la
urmǎtoarea face parte din acţiunea descrisǎ de acest altgoritm, înseamnǎ cǎ apelul este recursiv.
Vom demonstra cǎ altgoritmul recursiv urmeazǎ corect paşii metodei Backtracking
generalizat.
Presupunem ca altgoritmul descries pentru o componentǎ k se încheie la epuizarea
valorilor posibile pentru aceasta. În aceastǎ situaţie se revenea la componenta anterioarǎ, reluând
testǎrile pentru aceastǎ componentǎ. Într-un apel recursiv, la încheierea execuţiei acestuie se
revine la programul apelant – în cazul nostru am fǎcut apel din altgoritmul corespunzǎtor lui k-1,
deci aceastǎ întoarcere nu trebuie fǎcutǎ explicit.
Altgoritmul general în varianta recursivǎ ar putea avea forma:

procedure BKTGR(k:integer);
begin
INIT(k);
while EXISTA(k) do
begin
d[k]:=d[k]+1;
VALPOS(k,d);
if CONT(k) then
if SOLUTIE(k) then
TIPAR(k)
else
BKTGR(k+1)
end;
end;
Celelalte funcţii care apar au aceeaşi semnificaţie şi implementare ca şi în varianta
nerecursivǎ.
În programul principal procedura se va apela având ca parametru prima componentǎ
pentru cǎ aceasta se va completa prima. Se observǎ cǎ altgoritmul se va încheia atunci când vor fi
testate toate valorile posibile pentru aceastǎ componentǎ şi deci seria de apeluri este încheiatǎ.

17
program labirintul; function EXISTA(k:integer):boolean;
uses crt; begin
type component=record EXISTA:=d[k]<4;
l,c:integer; end;
end; procedure VALPOS(k:integer);
vectsol=array[1..100]of component; begin
auxiliar=array[1..100]of 0..4; x[k].l:=x[k-1].l+depl[d[k]].l;
labirint=array[1..25,1..25]of 0..2; x[k].c:=x[k-1].c+depl[d[k]].c;
const depl:array[1..4]of component= end;
((l:-1;c:0),(l:0;c:1), (l:1;c:0), function CONT(k:integer):boolean;
(l:0;c:-1)); var i:integer;
var x:vectsol; begin
d:auxiliar; CONT:=true;
tab:labirint; for i:=1 to k-1 do
n,m:integer; if(x[i].l=x[k].l)and
l0,c0:integer; (x[i].c=x[k].c)then
procedure citire; CONT:=false;
var i,j:integer; with x[k] do
begin if tab[l,c]=0 then
clrscr; CONT:=false;
writeln('configuratia labirintul:'); end;
write('m=');readln(m); function SOL(k:integer):boolean;
write('n=');readln(n); begin
writeln('Se codifica astfel: with x[k] do
1-culoar; 0-zid'); SOL:= (l=1)or(c=1)or
for i:=1 to m do (l=m)or(c=n)
for j:=1 to n do end;
begin procedure TIPAR(k:integer);
write('tab[',i,',',j,']='); var i,j:integer;
readln(tab[i,j]); begin
end; for i:=1 to k do
writeln('Pozitia initiala: '); with x[i] do
write('l0=');readln(l0); writeln(l,' ',c);
write('c0=');readln(c0); readln;
x[1].l:=l0; end;
x[1].c:=c0;
end; procedure BKTGR(k:integer);
procedure INIT(k:integer); begin
begin INIT(k);
d[k]:=0; while EXISTA(k) do
end; begin
18
d[k]:=d[k]+1; end
VALPOS(k); end;
if CONT(k)then begin
if SOL(k)then CITIRE;
TIPAR(k) BKTGR(2);
else end.
BKTGR(k+1);

BIBLIOGRAFIE:

1. L. Ţoca, A. R. Demco, C. Opincaru, A. Sindile


Informaticǎ – Manual pentru clasa a X-a
Editura Niculescu - Bucureşti, 2000

2. Fl. Munteanu, T. Ionescu, Gh. Muscǎ, D. Saru, S. M. Dascǎlu


Programarea calculatoarelor – Manual pentru liceele de informaticǎ,
clasele X-XII
Editura Didacticǎ şi Pedagogicǎ – Bucureşti, 1995

3. S. Niculescu şi colaboratori
Bacalaureat şi atestat
Editura L&S, 1998

19

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