Sunteți pe pagina 1din 7

Programming Techniques

Backtracking Stoica Spahiu Cosmin


1

Lucrarea 5. Backtracking.


Prezentarea Tehnicii Backtracking
Aceast tehnic poate fi utilizat pentru rezolvarea problemelor de cutare. Cutarea
efectuat este exhaustiv, putnd fi folosit pentru generarea tuturor soluiilor posibile.
Se folosete n rezolvarea problemelor care ndeplinesc simultan urmtoarele condiii:
Soluia lor poate fi pus sub forma unui vector V = x
1
x
2
x
3
. x
n
, cu

x
1
A
1
. X
n
A
n

Mulimile A
1
, A
2
, A
n
sunt mulimi finite, iar elementele lor se afl ntr-o
ordine bine stabilit
Nu se dispune de o metod de rezolvare mai rapid
La ntlnirea unei astfel de probleme suntem tentai s generm toate elementele
produsului cartezian A
1
A
2
. A
n
. Aceasta nu este totui o rezolvare foarte
rezonabil. Timpul de execuie este att de mare, nct poate fi considerat infinit.
Dac de exemplu dorim s generm toate permutrile unei mulimi, genernd
produsul cartezian, am putea obine 1,1,1,.1, pentru ca apoi s constatm c nu am
obinut o permutare (cifrele nu sunt distincte), dei chiar de la a 2-a cifr se poate observa
c cifrele nu sunt distincte.
Tehnica Backtracking are la baz un principiu extrem de simplu: se construiete
soluia pas cu pas. Dac se constat c pentru o anumit valoare nu se poate ajunge la
soluie, se renun la acea valoare i se reia cutarea din punctul unde am rmas.


Prezentarea algoritmului
Pentru uurarea nelegerii metodei vom prezenta o rutin unic, aplicabil oricrei
probleme, rutin care utilizeaz noiunea de stiv.
se alege primul element x
1
, ce aparine lui A
1
;
presupunnd generate elementele x
1
x
k
, vom avea 2 posibiliti:
o nu s-a gsit un astfel de element, caz n care se reia cutarea, considernd
generate elementele x
1
x
k-1
, iar aceasta se reia de la urmtorul element A
k
,
rmas netestat.
o a fost gsit, caz n care se testeaz dac acesta ndeplinete anumite condiii
(rspunsul poate fi verificat de o funcie Validare care returneaz true sau
false).
o dac le ndeplinete, se testeaz dac s-a ajuns la soluie (se utilizeaz
funcia Soluie, care returneaz true dac s-a ajuns la soluie)
dac s-a ajuns la soluie, se tiprete i se continu algoritmul
pentru gsirea unei alte soluii, considerndu-se generate x
1
x
k,
iar
elementul x
k+1
se caut printre elementele mulimii A
k+1
rmase
netestate
dac nu s-a ajuns la soluie se reia algoritmul considerndu-se
generate elementele x
1
, x
k
, x
k+1

o dac nu le ndeplinete se reia algoritmul considernd generate x
1
x
k
, iar
elementul x
k+1
se caut printre elementele mulimii A
k+1
rmase netestate
Programming Techniques
Backtracking Stoica Spahiu Cosmin
2
Problema Reginelor.
O s exemplificm tehnica cutrii cu reveniri cu ajutorul unei probleme clasice:
cum putem amplasa N regine pe o tabl de ah cu dimensiuni N x N astfel nct acestea s
nu se atace dou cte dou.
Este evident c nu putem amplasa dect o singur regin pe linie sau pe coloan i
n final fiecare linie va avea amplasat cte o regin. De aceea vom ncerca amplasarea
linie cu linie, ncepnd cu prima linie. Atunci cnd ncercm s amplasm o regin pe o
linie ncepem cu prima coloan i continum cu urmtoarele, pn cnd gsim o poziie
valid. n momentul n care nu mai gsim nici o poziie valid pe o linie vom reveni la linia
anterioar, unde vom cuta urmtoarea poziie. S rezolvm, de exemplu, problema pentru
N = 4.

ncepem cu prima linie i prima coloan:

Pe cea de-a doua linie nu putem amplasa nici o dam pn pe cea de-a treia coloan:

Pe linia a treia nu putem amplasa nici o dam, de aceea vom reveni la linia anterioar
pentru urmtoarea opiune:

Programming Techniques
Backtracking Stoica Spahiu Cosmin
3
Pe linia a treia prima opiune valid este pe coloana a doua:

Dar acum nu mai avem nici o opiune valid pentru linia a patra. Revenim la linia a treia.
Dar nici aici nu mai avem nici o opiune valid. De aceea trebuie s revenim la linia a doua.
Este evident c aici nu mai avem ce face aa c se revine pn la linia a I-a:

Acum putem trece la linia a II-a:

Pe linia a treia putem amplasa o regin chiar pe prima coloan:

Programming Techniques
Backtracking Stoica Spahiu Cosmin
4
n fine, pe ultima linie avem urmtoarea opiune valid:

Backtracking-ul se poate implementa mai uor recursiv. Programul complet pentru varianta
recursiv este urmtorul:

#include "stdio.h"
#include "conio.h"
#include "math.h"

int ataca(int linie, int memorie[])
//aceasta funcie testeaz daca regina de pe linie este atacata de
reginele poziionate anterior. Este de fapt funcia de Validare
{
int i;
//luam pe rnd toate damele poziionate anterior
for(i=0;i<linie;i++)
//verificam daca cele 2 dame sunt pe aceeai coloana sau pe diagonal
if((memorie[linie]==memorie[i]) ||
(abs(memorie[i]-memorie[linie])==linie-i))
// se ataca, deci nu sunt corect poziionate.
return 1;
return 0; //daca am ajuns aici, nseamn c nu se atac
}



//cile de afiare sunt infinite
void afiseaza(int dim,int memorie[])
{
int l,c;
for(l=0;l<=dim;l++)
printf("_");
for(l=0;l<dim;l++)
{
printf("\n|");
for(c=0;c<dim;c++)
if(memorie[l]==c)
printf("%c",6);
else
if((l+c)&1)
printf(" ");
else
printf("%c",219);
printf("|");
}
printf("\n");
for(l=0;l<=dim;l++)
Programming Techniques
Backtracking Stoica Spahiu Cosmin
5
printf("-");
printf("\n");
printf("o tasta, va rog!\n");
getch();
}



void dame(int dim,int linie, int memorie[])
// aici este funcia care face efectiv backtracking-ul (suntem la
// linia(nivelul) linie.
// dim ne spune ct de mare-i tabla
// memorie tine minte damele deja poziionate. Ea este stiva
{
if(linie==dim)// daca am terminat
afiseaza(dim,memorie);//afim
else //altfel avem de lucru
for(memorie[linie]=0;memorie[linie]<dim;memorie[linie]++)
//ncercam toate coloanele de la stnga la dreapta
if(!ataca(linie,memorie))
//daca e o poziie valida trecem la nivelul urmtor
dame(dim,linie+1,memorie);
//cnd ne ntoarcem din apelul recursiv nseamn c am revenit
// la acest nivel i ncercm urmtoarea coloana
}

void main()
{
int n,memorie[100];
printf("dimensiunea tablei de joc=");
scanf("%d",&n);
dame(n,0,memorie);// prima linie are numrul zero
}



n continuare prezentm i o implementare iterativ:

#include "stdio.h"
#include "conio.h"
#include "math.h"

int ataca(int linie, int memorie[])
//aceleai explicaii ca mai sus, dar nu de alta dar e aceeai funcie
{
int i;
for(i=0;i<linie;i++)
if((memorie[linie]==memorie[i]) ||
(abs(memorie[i]-memorie[linie])==linie-i))
return 1;
return 0;
}

void afiseaza(int dim,int memorie[])
//la fel ca mai sus
{
int l,c;
for(l=0;l<=dim;l++)
printf("_");
for(l=0;l<dim;l++)
{
Programming Techniques
Backtracking Stoica Spahiu Cosmin
6
printf("\n|");
for(c=0;c<dim;c++)
if(memorie[l]==c)
printf("%c",6);
else
if((l+c)&1)
printf(" ");
else
printf("%c",219);
printf("|");
}
printf("\n");
for(l=0;l<=dim;l++)
printf("-");
printf("\n");
printf("o tasta, va rog!\n");
getch();
}

void main()
{
int n,memorie[100],nivel;
printf("dimensiunea tablei de joc=");
scanf("%d",&n);
nivel=0;
//datorit C-ului primul nivel are numrul zero
//punem prima dam s se nclzeasc pe marginea tablei
memorie[nivel]=-1;
//ct timp nu ncercm s poziionm dama de linia -1
while(nivel>=0)
{
if(nivel==n) //avem o soluie
{
afiseaza(nivel,memorie);
//ne ntoarcem la ultima linie
nivel--;
}
//ncercm urmtoarea poziie de pe linia curent
memorie[nivel]++;
// dac dama a epuizat coloanele
if(memorie[nivel]==n)
//revenim la linia anterioar
nivel--;
else // altfel
//dac este o poziie valid
if(!ataca(nivel,memorie))
memorie[++nivel]=-1;
//trecem la urmtorul nivel i scoatem nc o dam la nclzire
}
}

Aceast tehnic este relativ uor de folosit, dar fiind foarte lent i consumatoare de
memorie este recomandabil pentru cazurile n care resursele nu sunt o problem.

Probleme propuse.

1. Se d un labirint cu N x M celule avnd forma unui ptrat, fiecare celul avnd
maxim o u pe fiecare latur (n total maxim 4 ui). Uile pot funciona ntr-un
Programming Techniques
Backtracking Stoica Spahiu Cosmin
7
singur sens. Se cere s se determine calea de la o celul oarecare ctre ieirea din
labirint.
2. Se d o hart cu n orae. Pe aceast sunt trasate m drumuri, care unesc oraele dou
cte dou. S se determine calea care leag dou orae oarecare.
3. S se determine toate mutrile pe care trebuie s le efectueze un cal pe o tabl de
ah astfel nct s treac prin toate poziiile cel puin o dat, pornind dintr-o poziie
oarecare.
4. S se determine toate mutrile pe care trebuie s le efectueze un cal pe o tabl de
ah astfel nct s treac prin toate poziiile o singur dat, pornind dintr-o poziie
oarecare.
5. Se dau x plci de gresie de dimensiuni 1x1, fiecare plac avnd fiecare margine
vopsit ntr-o culoare. S se determine cum poate fi pavat o ncpere de
dimensiuni N x M astfel nct marginile vecine ale plcuelor s aib aceeai
culoare.
6. Se dau x plci de gresie de dimensiuni 1x1, fiecare plac fiind vopsit ntr-o
culoare. S se determine cum poate fi pavat o ncpere de dimensiuni N x M astfel
nct dou plcue vecine s nu aib aceeai culoare.

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