Sunteți pe pagina 1din 6

O modalitate de nvare a metodei backtracking

prof. Doru Popescu Anastasiu, Slatina



n memoria lui Tudor Sorin.

Rezumat
n urm cu aproximativ 16 de ani Tudor Sorin propunea lumii informatice din Romnia
un ir de materiale prin care standardiza metoda backtracking. Acest lucru a dus la
crearea unui ablou prin care o metod putea fi folosit deopotriv de ctre elevi,
studeni, profesori. n continuare voi prezenta aceast metod de programare ca o
continuare fireasc a capitolului Recursivitate din clasa a X-a, profil matematic-
informatic, intensiv informatic.

Introducere

Muli profesori ncheie capitolul recursivitate cu probleme de tipul:

Se d un numr natural n<20 i un alfabet cu dou litere (A={a,b}). Determinai toate
cuvintele de n litere folosind alfabetul dat.
Exemplu
cuvinte.in cuvinte.out
2 aa
ab
ba
bb

Rezolvarea problemei fiind urmtoarea:

Un cuvnd poate fi memorat ntr-un vector x cu n componente de tip char (fiecare
component putnd s aib una din valorile a,b). Recursiv, cuvintele se pot
determina folosind programul urmtor:

var x:array[0..21]of char;
n:integer;
f:text;

procedure afisare;
var i:integer;
begin
for i:=1 to n do
write(f,x[i]);
writeln(f);;
end;
#include <fstream.h>

char x[21];
int n;
ofstream fout("cuvinte.in");

void afisare(){
int i;
for(i=1;i<=n;i++)
fout<<x[i];
fout<<'\n';
}


procedure generare(k:integer);
begin
if k=n+1 then
afisare
else
begin
x[k]:='a';
generare(k+1);
x[k]:='b';
generare(k+1);
end
end;

begin
assign(f,'cuvinte.in');
reset(f);
read(f,n);
close(f);
assign(f,'cuvinte.out');
rewrite(f);
generare(1);
close(f)
end.

void generare(int k){
if(k==n+1)
afisare();
else
{
x[k]='a';
generare(k+1);
x[k]='b';
generare(k+1);
}
}

int main(){
ifstream fin("cuvinte.in");
fin>>n;
fin.close();
generare(1);
fout.close();
return 0;
}


Pentru exemplul dat n enun irul de apeluri este urmtorul:

generare(1) generare(2) generare(3)
x[1]=a x[2]=a
se stopeaz generarea prin condiia k=n+1 i
se afieaz aa

x[2]=b
generare(3)
se stopeaz generarea prin condiia k=n+1 i
se afieaz ab
x[1]=b
generare(2) generare(3)
x[2]=a
se stopeaz generarea prin condiia k=n+1 i
se afieaz ba

x[2]=b
generare(3)
se stopeaz generarea prin condiia k=n+1 i
se afieaz bb
stop


Se obine astfel urmtorul arbore, cu evoluia vectorului x:

Generalizri

Ne punem n continuare problema, cum putem determina cuvintele care folosesc un
alfabet mai mare (de exemplu cu primele m litere din alfabetul englez). Mai mult, cum
determinm cuvintele care ndeplinesc o anumit proprietate (de exemplu: s nu aib
dou litere la fel pe poziii consecutive) .a.m.d.

Dac ne concentrm pe problema determinrii cuvintelor, folosind primele m litere din
alfabetul englez cu restricia: s nu existe litere egale pe poziii consecutive, o variant de
subprogram ce genereaz vectorul x ar putea fi:

procedure generare(k:integer);
var i:integer;
begin
if k=n+1 then
afisare
else
for i:=1 to m do
begin
x[k]:=chr(ord(a)+i-1);
generare(k+1)
end
end;
void generare(int k){
int i;
if(k==n+1)
afisare();
else
for(i=1;i<=m;i++)
{
x[k]='a'+i-1;
generare(k+1);
}
}


Menionm faptul c, n funcia de afiare se va verifica condiia ca s nu existe dou
litere egale pe poziii consecutive, afiarea fcndu-se numai n acest caz.

n aceste condiii pentru n=2 i m=2 se genereaz acelai arbore ca mai sus. Unele dintre
ramuri fiind generate degeaba, pentru c odat construite dou componente cu indici
consecutivi i aceai liter, sigur nu se va ajunge la un cuvnt ca s fie afiat. Astfel
pentru a eficientiza algoritmul de generare se impune adugarea unei condiii la fiecare
pas (legat de alegerea valorii pentru componenta x[k], adic x[k]x[k-1]).

Obinem astfel rafinarea:


x=()
x=(a) x=(b)
x=(a,a) x=(a,b) x=(b,a) x=(b,b)

procedure generare(k:integer);
var i:integer;
begin
if k=n+1 then
afisare
else
for i:=1 to m do
begin
x[k]:=chr(ord(a)+i-1);
if conditie(k) then
generare(k+1)
end
end;
void generare(int k){
int i;
if(k==n+1)
afisare();
else
for(i=1;i<=m;i++)
{
x[k]='a'+i-1;
if(conditie(k))
generare(k+1);
}
}


Funcia condiie returneaz true/1 sau false/0 n funcie de situaie (dac x[k]x[k-1],
respectiv x[k]=x[k-1]). Pentru a nu avea un caz particular k=1, nainte de apelul
generare(1) se face iniializarea lui x[0] cu un caracter care nu este n alfabet (de
exemplu x[0]=*).

Trecerea la metoda backtracking

Folosind consideraiile anterioare putem s discutm despre rezolvarea unei probleme
generale.

Metoda backtracking permite s se rezolve probleme de tipul:

Se dau n mulimi A
1
, A
2
, ..., A
n
i o proprietate P, care depinde de x
1
, x
2
, ..., x
n
(x
1
din A
1
,
x
2
din A
2
, ..., x
n
din A
n
). Se cere s se determine toate irurile x
1
, x
2
, ..., x
n
, care verific
proprietatea P.

Particularizare
Pentru problema cu generarea cuvintelor n care literele de pe poziii consecutive sunt
distincte, avem:

A
1
, A
2
, ..., A
n
sunt toate formate din primele m litere mici ale alfabetului englez.
P este condiia x
i
x
i-1
, i din mulimea {2,3, , n}.

Descrierea metodei de rezolvare (numit bactracking datorit mecanismului de generare
a soluiilor)

- Construirea componentelor vectorului x se va face n ordinea cresctoare a indicilor, x
1
,
x
2
, ..., x
k
, ..., x
n
. x
k
fiind din multimea A
k
.

- Din condiia P se deduc condiii parilale, pentru componentele x
1
, x
2
, ..., x
k
. Acestea
vor fi notate cu P(k).

- Ideea metodei const n faptul c dac, la un mont dat trebuie s se construiasc x
k
, se
consider pe rnd elementele lui A
k
i dac sunt verificate condiiile P(k), atunci se trece
la urmtoarea component, altfel se merge napoi la componenta anterioar i se caut
alt valoare. n permanen exist un dute-vino (realizat de mecanismul recursivitii)
pn se ajunge la cte o soluie.

- Forma general a unui subprogram recursiv de generare a vectorului x este prezentat n
continuare.

procedure back(k:integer);
var i:Tip;
begin
if k=n+1 then
afisare
else
for i din A
k
do
begin
x[k]:=i;
if P(k) then
back(k+1)
end
end;
void back(int k){
Tip i;
if(k==n+1)
afisare();
else
for(i din A
k
)
{
x[k]=i;
if(P(k))
back(k+1);
}
}


- Subprogramul de generare trebuie apelat prin back(1), pentru a construi vectorul x
ncepnd cu prima component.

Observaii

- Metoda backtracking determin toate soluiile problemei.
- Cu ct condiiile pariale P(k) sunt mai restrictive cu att timpul de execuie este mai
mic.
- Uneori este de preferat s folosim n componentele lui x, indicii elementelor din
mulimile A
1
, A
2
, ..., A
n
, pentru c acetia sunt numere consecutive i pot fi parcuri mai
uor.
- Timpul de execuie al algoritmilor ce folosesc metoda backtracking este exponeial
(relativ la n).
- Dac exist alte metode de rezolvare cu timp de execuie polinomial, atunci aceast
metod poate fi folosit doar pentru a confirma corectitudinea celeilate, prin compararea
rezultatelor.
- Pentru a nsui aceast metod de programare este nevoie de rezolvarea unui numr
mare de probleme, ncepnd cu cele clasice (problema damelor, colorarea unei hri,
generarea elementelor combinatoriale, plata unei sume de bani, etc.), apoi continund cu
cele care necesit modificri ale subprogramului de generare.
- Metoda backtracking poate fi utilizat i pentru generri de lanuri n tablouri
bidimensonale (aa numitul backtracking n plan) ns pentru aceast variant ar trebui s
scris un alt material.

Probleme propuse

1. Se d o mulime A cu n (n<20) elemente numere naturale <32000. Se cere s se
determine toate modalitile de mprire a lui A n trei mulimi cu aceeai sum a
elementelor.
Exemplu
multime.in multime.out
9
2 8 7 11 6 4 9 3 10
{7 3 6 4} {2 8 10} {11 9}
...

2. Se d un ir cu n (n<50) elemente numere naturale <100. Se cere s se determine toate
numere din ir, care se pot scrie ca sum de numere prime distincte.
Exemplu
sir.in sir.out
3
6 7 10
7 10

3. Se d n numr natural (n<20). Determinai toate numerele n baza 2 cu n cifre, care au
numrul de cifre de 1 egal cu cel al celor de 0.
Exemplu
baza2.in baza2.out
4 1100
1010
1001

4. Se d un ir cu n (n<20) elemente, numere naturale <200 distincte. Se cere s se
determine cel mai mic numr natural, care nu poate fi scris ca o sum de termeni din irul
dat.
Exemplu
mic.in mic.out
4
1 2 4 10
8

5. Se d un ir cu n (n<20) elemente, numere naturale <200 distincte. Se cere s se
determine toate subirurile cresctoare de lungime maxim ale irului dat.
Exemplu
subsir.in subsir.out
7
8 3 5 9 2 3 4
3 5 9
2 3 4

6. Se d un ir cu n (n<20) elemente, numere ntregi cu valoarea absolut <200. Se cere
s se determine toate valorile epresiilor aritmetice ce se pot obine punnd ntre orice
dou numere vecine operatorul + sau -.
Exemplu
exp.in exp.out Explicatie
3
2 8 -2
8
12
-8
-4
2+8+(-2)
2+8-(-2)
2-8+(-2)
2-8-(-2)

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