Sunteți pe pagina 1din 7

CAPITOLUL 9.

METODA BACKTRACKING

Se aplică pentru problemele în care soluţia poate fi reprezentată sub forma unui vector
X=(x[1],x[2],...,x[k]).
X∈S[1]xS[2]x...xS[n]
S[1]xS[2]x...xS[n] - se numeşte spaţiul soluţiilor posibile.
|S[i]|=s[i], S[i]={a[i,1],a[i,2],...,a[i,s[i]]}
Între componentele vectorului X sunt date mai multe condiţii interne, care depind de natura
problemei date. Soluţiile posibile pentru care sunt verificate condiţiile interne le numim soluţii
rezultat. În unele probleme se cere alegerea dintre soluţiile rezultat a soluţiei optime după un
anumit criteriu.
Observaţii:
Astfel de probleme pot fi rezolvate prin generarea tuturor elementelor produsului cartezian
S[1]xS[2]x...xS[n] (întreg spaţiul soluţiilor), dar această metodă nu este eficientă. Această
metodă se numeşte metoda forţei brute – brute-force.
Soluţie parţială = o soluţie pentru care sunt îndeplinite condiţiile de continuare. Condiţiile de
continuare sau de validare se obţin din condiţiile interne aplicate pentru o soluţie parţială.
Construirea soluţiei:
− Soluţia se construieşte sub forma unei stive, astfel încât la fiecare pas se alege o valoare
pentru elementul curent x[k] (soluţia se construieşte progresiv). La început k=1 şi x[1]
se iniţializează cu o valoare anterioară primei valori din S[1].
− Cât timp stiva nu este vidă, completăm soluţia parţială cu noi componente.
Elementului x[k] din vârful stivei i se atribuie următoarea valoare din mulţimea S[k]
(dacă există).
Pentru soluţia parţială obţinută (x[1],x[2],...,x[k]) sunt verificate condiţiile de validare.
Apar astfel două posibilităţi:
1) Condiţia de continuare este adevărată:
- în acest caz testăm egalitatea k==n, adică verificăm dacă avem valori pentru toate
componentele vectorului soluţie. În caz afirmativ, am obţinut o soluţie a problemei, pe care o
reţinem.
- În cazul k<n incrementăm k cu 1 şi iniţializăm x[k] cu o valoare anterioară primei valori din
mulţimea S[k].
2) În situaţia în care condiţia de continuare este falsă, alegem pentru x[k] următoarea valoare
posibilă din S[k] şi verificăm din nou condiţiile de validare. Dacă nu se poate face altă alegere,
revenim pe stivă la nivelul anterior şi verificăm următoarea valoare pentru x[k-1].

Pentru orice problemă particulară care este rezolvată prin metoda backtracking trebuie
precizate:
(1) spaţiul soluţiilor, adică mulţimile S[1],S[2],...,S[n]. Nu este necesar ca aceste mulţimi să
aibă acelaşi număr de elemente.
(2) condiţiile de validare a unei soluţii parţiale (x[1],x[2],...,x[k]). Alegerea acestor condiţii
influenţează decisiv eficienţa metodei.
Rutina backtracking (varianta iterativă)
int x[31],n;

void back()
{
int k=1;
x[k]=init(k);
while (k>0)
{
while (există o valoare netestată în Sk)
{
x[k]=urmator(k);
if valid(x[1],x[2],...,x[k])
if (k==n) solutie(x[1],x[2],...,x[n]);
else {
k=k+1;
x[k]=init(k);
}
}
k=k-1;
}
}

Rutina backtracking (varianta recursivă)


int x[31],n;
void back(int k)
{
x[k]=init(k);
while (are_succesor(x[k]))
if valid(k)
if (este_solutie(k)) solutie();
else back(k+1);
}
Probleme celebre:
1. Problema colorării hărților:
Fiind dată o hartă cu n tări, se cer toate modalităţile de colorare a hărţii, utilizând cel mult p
culori, astfel încât două ţări cu frontieră comună să fie colorare diferit. Este demonstrat faptul
că sunt suficiente numai 4 culori ca orice hartă să poată fi colorată.
Pentru rezolvare se vor folosi:
k: variabilă întreagă, care reprezintă o ţară
sol: vector cu componente întregi cu proprietatea sol[k] reprezintă culoarea ţării cu numărul k
deoarece sunt n ţări şi p culori, k={1,...,n} şi sol[k]={1,...,p}
sol=(sol1,sol2,...,soln) unde sol[k]∈{1,...,n}.
Pentru reprezentarea hărții în program se va folosi matricea de adiacență, definită astfel:

#include <iostream>
using namespace std;
int n, k, sol[20], p, a[20][20];
void init(int k)
{
sol[k]=0;}

int succesor (int k)


{
if(sol[k]<p)
{
sol[k]=sol[k]+1;
return 1;
}
else
return 0;
}
int valid(int k)
{
int ev=1,i;
for(i=1;i<k;i++)
if(a[i][k]==1&& sol[i]==sol[k])
ev=0;
return ev;
}
int solutie(int k)
{
return(k==n+1);}
void tipar()
{
int i;
for(i=1;i<=n;i++)
cout<<sol[i];
cout<<endl;
}
void back (int k)
{
if(solutie(k))
tipar();
else
init(k);
while(succesor(k))
if(valid(k))
back(k+1);
}
int main()
{int i,j;
cout<<"n=";
cin>>n;
cout<<"p=";
cin>>p;
for(i=1;i<n;i++)
for(j=i+1;j<=n; j++)
{
cin>>a[i][j];
a[j][i]=a[i][j];
}
back(1);
return 0;}

2. Problema plății unei sume de bani cu monede de diferite tipuri


Se dau suma S și m tipuri de monede având valorile a1, a2, …, am lei. Se cer toate mosalitățile
de plată a sumei S utilizând aceste monede.
SOLUTIE:
− Se vor genera toți vectorii de forma X=(x1, x2, …, xm) care verifică relația
x1⋅a1 + x2⋅a2 + … + xm⋅am = S.
− Din această relație se observă că:
!
x1 poate lua valori între 0 și n1=
"#
!
x2 poate lua valori între 0 și n2=
"$

…………………………………….
!
xm poate lua valori între 0 și nm=
"%
#include <iostream>
using namespace std;
int n[20],k,sol[20],a[20],m,S;
void init(int k)
{
sol[k]=-1;
}
int succesor (int k)
{
if(sol[k]<n[k])
{
sol[k]=sol[k]+1;
return 1;
}
else return 0;
}
int valid(int k)
{
return 1;
}
int solutie(int k)
{
return(k==m);
}
void tipar()
{
int i,s1=0;
for(i=1;i<=m;i++)
s1=s1+sol[i]*a[i];
if(S==s1)
{
for(i=1;i<m;i++)
cout<<sol[i]<<"*"<<a[i]<<"+";
cout<<sol[m]<<"*"<<a[m]<<"="<<S<<endl;
}
}

void back (int k)


{
if(solutie(k))
tipar();
else
init(k);
while(succesor(k))
if(valid(k))
back(k+1);
}
int main()
{int i;
cout<<"Suma=";
cin>>S;
cout<<"numarul de monede=";
cin>>m;
cout<<"valorile monedelor sunt"<<endl;
for(i=1;i<=m;i++)
{
cin>>a[i];
n[i]=S/a[i];
}
back(1);
return 0;}

3. Problema damelor:
Fiind dată o tablă de șah de dimensiune n x n, se cer toate modalitățile de aranjare a n dame
astfel încât să nu existe două dame pe aceeași linie, aceeași coloană sau aceeași diagonala (adică
damele să nu se atace reciproc).
Pentru rezolvare se vor folosi:
− k reprezentând numărul liniei pe care s-a așezat a k-a damă
− x vector cu componente întregi cu proprietatea că xk reprezintă coloana pe care s-a așezat
a k-a damă
Se observă că:
− dama k și dama i nu se află niciodată pe aceeași linie datorită modului de generare a
vectorului x
− dama k și dama i se află pe aceeași coloană dacă xk=xi
− dama k și dama i se află pe aceeași diagonală dacă k-i=| xk=xi |
#include <iostream>
using namespace std;
int n,k,x[20];
void init(int k)
{
x[k]=0;
}
int succesor (int k)
{
if(x[k]<n)
{
x[k]=x[k]+1;
return 1;
}
else return 0;
}
int valid(int k)
{
for(int i=1;i<=k-1;i++)
if((x[k]==x[i])||(k-i==x[k]-x[i])||(k-i==x[i]-x[k]))
return 0;
return 1;
}
int solutie(int k)
{
return(k==n);
}
void tipar()
{
int i;
for(i=1;i<=k;i++)
cout<<x[i]<<" ";
cout<<endl;
}

void back (int k)


{
if(solutie(k))
tipar();
else
init(k);
while(succesor(k))
if(valid(k))
back(k+1);
}
int main()
{
cout<<"n=";
cin>>n;
back(1);
return 0;
}

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