Documente Academic
Documente Profesional
Documente Cultură
Spațiul soluțiilor
În multe probleme soluțiile pot fi descrise ca vectori cu n elemente x=( x 1 , x 2 , … , x n ) unde
x i ∈ S i , i=1 , … , n
S=S 1 × S 2 × …× S n= { x=( x 1 , x 2 , … , x n )∨x i ∈ S i } spațiul soluțiilor
i=1 , n : card ¿, și pe Si este definită o relație de ordine totală
φ : S → { da , nu } funcție de validare
R={ x ∈ S∨φ ( x )=da } mulțimea soluțiilor rezultat
φ ( x )=da ⟺ x ∈ R
φ k : S1 × S2 ×… × S k → { da , nu } funcții de validare parțială
φ k−1=da ⇒ se poate adăuga un element x k ∈ S k cu φ k =da
φ k−1=nu ⇒ nu se poate adăuga un element x k ∈ S k cu φ k =da
Backtracking – operații
Atribuie și avansează - x i ← v i , φi ( x1 , x 2 , … , xi ) =da,C i ← Ci ∪ { v i }
… v i−1 xi x i+1 … … v i−1 vi x i+1 …
( |
… C i−1 C i ∅ …
→
) (
… C i−1 Ci ∪ { v i } ∅ … | )
Încercare eșuată - x i ← v i , φi ( x1 , x 2 , … , xi ) =nu ,C i ← Ci ∪ { v i }
x i rămâne neatribuit
… v i−1 xi x i+1 … … v i−1 xi x i+1 …
( |
… C i−1 C i ∅ …
=¿=
) (
… C i−1 C i ∪ { v i } ∅ … | )
Revenire după o încercare eșuată, cu epuizarea variantelor ( C i=Si )
… v i−1 xi xi +1 … … v i−2 x i−1 x i …
( |
… C i−1 Si ∅ …
←
) ( |
… C i−2 Ci −1 ∅ … )
Revenire după construirea unei soluții
… v n−1 v n … v n −1 x n
( … C n−1 C n
⋘
|) (
… C n−1 Cn |)
Backtracking - implementare recursivă
Metoda este de natură recursivă, deci ușor de implementat recursiv
Forma recursivă generală
backtracking(i)
dacă i==n+1
retine_solutia()
altfel
pentru fiecare element j din S i
x[i]=j;
daca posibil(i)
call backtracking(i+1)
Backtracking – implementare iterativă
inițializare S1 , S 2 , … , S n
C i=∅ ,i=1, n //construire configurație inițială
i=1
cât timp i>0 //cât timp configurația nu e finală
◦ dacă i=¿ n+1 //configurație de tip soluție?
reține soluția Sol= ( x1 , x2 , … , xn )
i=i−1 //revenire după construirea unei soluții
◦ altfel
dacă C i ≠ S i //mai sunt valori neconsumate
alege o valoare vi ∈ Si −Ci
C i=Ci ∪ { vi }
dacă ( v ¿ ¿1 , v 2 , … , v i−1 , v i) ¿ satisface condițiile de continuare
x i=vi //atribuie și avansează
i=i +1
//altfel încercare eșuată
altfel //revenire
C i=∅
i=i−1
Backtracking – variantă
Particularități ale unor probleme
◦ Si - progresii aritmetice cu termen inițial a i, rația r i și termen final si
uneori a i=1, r i=1
◦ toate Si sunt identice cu mulțimea { 1,2 , … , n }
◦ Avantaje
◦ nu trebuie memorate explicit mulțimile Si și C i
◦ alegerea unui element neconsumat este ușoară
◦ a i, a i+r , a i+2∗r , ai +3∗r , …, , x i−r , x i, x i+ r , … , si
i=1
x i=a i−r i //primul element minus rația, adesea 0=1-1
cât timp i>0
◦ dacă i=¿ n+1 //configurație de tip soluție?
reține soluția Sol=( x 1 , x 2 , … , x n )
i=i−1 //revenire după construirea unei soluții
◦ altfel
vb=0 //variabila de impas
cât timp x i< s i și vb=¿ 0 //alegere nouă valoare x i
x i=x i+ r i //următorul termen
vb=posibil( x i)// verficare condiții de continuare
dacă vb=¿ 0 //impas => revenire
i=i−1
altfel //avans
i=i +1
x i=a i−r i
Exemple de probleme care se rezolvă prin metoda backtracking:
◦ Problema celor 8 ◦ Generarea ◦ Problema
(n) regine. tuturor permutărilor. colorării hărților.
◦ Problema ◦ Generarea
cavalerilor mesei rotunde. tuturor aranjamentelor.
◦ Plata unei sume ◦ Generarea
(cu/fără bancnotă unitate). tuturor combinărilor.
Condiție de continuare
Regina plasată, i
nu e pe aceeași linie cu una plasată anterior
implicit, nu e nevoie de verificare
nu e pe aceeași coloană cu una plasată anterior
x i ≠ x j pentru j=1 ,i−1
nu e pe aceeași diagonală cu una plasată anterior
|i− j|≠|x i−x j| pentru j=1 ,i−1
Condiţie finală nu e necesară
//retine solutia - afisarea solutiei sol, a nrs-a
void retine_solutia(int nrs, int n, int *sol) //verificare indeplinire conditie de continuare
{ int posibil(int n, int k, int *x)
cout<<"Solutia "<<nrs<<"\n"; {
int i,j; int i;
for(i=0;i<n;i++){ int OK=1;
for(j=0;j<n;j++) for (i=0;i<k && OK;i++)
if(sol[i]==j) if((abs(i-k)==abs(x[i]-x[k]))||
cout<<"R "; (x[i]==x[k]))
else OK=0;
cout<<"* "; return OK;
cout<<endl; }
}}
//implementarea recursiva {
int regine_r(int nrs, int n, int i, int *x) int j;
if(i==n){
nrs++;
retine_solutia(nrs,n,x);
}
else
for(j=0;j<n;j++){
x[i]=j;
if (posibil(n,i,x))
nrs=regine_r(nrs,n,i+1,x);
}
return nrs; }
//implementare iterativa
int regine_i(int n)
{
int i,j,p,nrs;
int *x=new int[n+1];
i=0;x[0]=-1;nrs=0;
while(i>=0)
if(i==n){
nrs++;retine_solutia(nrs,n,x);i-
}
else{
p=0;
for(j=x[i]+1;j<n && !p;j++){
x[i]=j;
p=posibil(n,i,x); }
if(p){i++;x[i]=-1;}
else i--;
}
delete x; return nrs;}