Documente Academic
Documente Profesional
Documente Cultură
7.2.metoda Backtracking
7.2.metoda Backtracking
G
Notiuni teoretice
Deoarece mulţimile Sk, cu k=1,n, sunt mulţimi finite, atunci fiecare element al
mulţimii poate fi identificat prin indicele său, urmând ca informaţia aferentă
elementului de indice k să fie conţinut intr-o zonă de date. În concluzie, în
vectorul x, în pozitia k vom depune valorile 1 pina la nk, unde nk reprezinta
cardinalul multimii Sk. Astfel, alegerea elementelor de pe poziţia k se va
face în ordinea crescătoare a indicilor.
Presupunând condiţiile de continuare stabilite, putem scrie procedura
BACKTRACK, in care CONT reprezintă condiţiile de continuare pentru x1,...,
xk, iar ESTE_SOL reprezintă condiţia ca x1, ..., xk să reprezinte o soluţie.
Cea mai intuitivă metodă este cea care foloseşte implementarea recursivitatii.
Algoritmul în pseudocod este prezentat mai jos:
procedura BACKTRACK(k) este
| pentru i=1,nk,1 repetă
| | xk ← i
| | dacă CONT(x,n,k)=1 atunci
| | | dacă ESTE_SOL(x,k) atunci
| | | | *scrie x1, ..., xk
| | | |_▄
| | | execută BACKTRACK(k+1)
| | |_▄
| |_▄
|_▄
- varianta recursivă
procedura BACKTRACK(k) este
| pentru i=1,nk,1 repetă
| | xk ← i
| | dacă CONT(x,n,k)=1 atunci
| | | dacă ESTE_SOL(x,k) atunci
| | | | * scrie x1, ..., xk
| | | | altfel execută BACKTRACK(k+1)
| | | |_▄
| | |_▄
| |_▄
|_▄
- varianta iterativă
procedura BACKTRACK(x,n) este :
| k←1
| xk ← 0
| cât timp k>0 repeta
| | gasit ← 0
| | i ← xk+1
| | ┌ cât timp ink si gasit=0 repetă
| | | xk ← i
| | | dacă CONT(x, n, k)=1 atunci
| | | | gasit ←1
| | | | altfel i ← i+1
| | | |_▄
| | |_▄
| | dacă gasit=0 atunci
| | | k ← k-1
| | | altfel dacă ESTE_SOL(x, k, n)=1 atunci
| | | | * scrie x1, ..., xk
| | | | altfel k ← k+1
| | | | xk ← 0
| | | |_▄
| | |_▄
| |_▄
|_▄
Implementarea metodei Backtracking se poate face iterativ folosind o stivă.
Astfel elementele x1, x2, ..., xk le putem imagina într-o stivă notată ST.
xk
…
x2
x1
ST
Gasirea elementelor xk+1 determină urcarea în stivă pe nivelul k+1, în caz con
trar se coboara la nivelul k-1. Când se ajunge la nivelul 0 algoritmul se termin
ă.
Algoritmul pseudocod este urmatorul:
Pe un anumit nivel k se cauta succesorul, atât timp cât există succesor care nu
este valid.
Variabila AS are rolul de a reţine dacă, atunci când s-a ieşit din ciclu, am avut s
uccesor, caz în care acesta este valid (contrar nu s-ar fi ieşit din ciclu).
Toate variabilele, cum ar fi stiva ST şi nivelul la care s-a ajuns k, sunt globale.
Această metodă folosind o stivă se poate trata si recursiv, adică procedura BA
CK(k) va fi recursivă, şi va primi ca parametru nivelul k.
D
D
D
D
D D D D
D D D
D D
D
Algoritmul continuă în acest mod, până când trebuie scoasă de pe tabla prima
dama.
Pentru reprezentarea unei soluţii putem folosi un vector cu n componente (avâ
nd în vedere că pe fiecare linie se găseşte o singura damă).
Pentru soluţia găsită avem vectorul st ce poate fi asimilat unei stive.
Doua dame se gasesc pe aceeaşi diagonală dacă şi numai dacă este îndeplinit
ă condiţia:
| st(i) – st(j) | = | i – j |
3 st(4)
1 st(3)
4 st(2)
2 st(1)
Exemplu: In tabla 4 x 4 situatia este urmatoarea:
D st(1) = 1 i=1
st(3) = 3 j=3
D | st(1) – st(3) | = | 1 – 3 | = 2
|i–j|=|1–3|=2
Sau:
D st(1) = 3 i=1
st(3) = 1 j=3
D | st(1) – st(3) | = | 3 – 1 | = 2
|i–j|=|1–3|=2
Programul in C – Exemplul 1 (varianta iterativa)
#include<stdio.h>
#include<conio.h>
#include<math.h>
int st[100],k,n;
void Init(){
st[k]=0;
}
int Succesor(){
if(st[k]<n){
st[k]++;
return 1;
}
else return 0;
}
int Valid(){
int i;
for(i=1;i<k;i++)
if((st[k]==st[i])||(abs(st[k]-st[i])==abs(k-i)))
return 0;
return 1;
}
int Solutie(){ return (k= =n); }
void Tipar(){
int i;
for(i=1;i<=n;i++) printf("%d ",st[i]);
printf("\n"); getch();
}
void Back(){
int AS=0;k=1;
Init();
while(k>0){
do{ }while((AS=Succesor())&& (!Valid()));
if(AS)
if(Solutie()) Tipar();
else{
k++;
Init();
}
else k--;
}
}
void main(){
printf("n=");scanf("%d",&n);
Back();
}
Programul in C – Exemplul 1 (varianta recursiva)
#include<stdio.h>
#include<conio.h>
#include<math.h>
int st[100],k,n;
void Init(int k){
st[k]=0;
}
int Succesor(int k){
if(st[k]<n){
st[k]++;
return 1;
} else return 0;
}
int Valid(int k){
int i;
for(i=1;i<k;i++) if((st[k]==st[i])||(abs(st[k]-st[i])==abs(k-i))) return 0;
return 1;
}
int Solutie(int k){
return (k= =n+1);
}
void Tipar(){
int i;
for(i=1;i<=n;i++) printf("%d ",st[i]);
printf("\n"); getch();
}
void Back(int k){
if(Solutie(k)) Tipar();
else {
Init(k);
while (Succesor(k)){
if (Valid(k)) Back(k+1);
}
}
}
void main(){
clrscr();
printf("n=");scanf("%d",&n);
Back(1);
}
Exemplul 2. Problema colorării hărţilor. Fiind dată o hartă cu n ţări, se cer toat
e soluţiile de colorare a hărtii, utilizând cel mult patru culori, astfel încât două ţă
ri cu frontiera comună să fie colorate diferit.
Pentru exemplificare, vom considera următoarea hartă, unde ţările sunt numer
otate cu cifre cuprinse intre 1 si 5.
1
2
4
3
Se va utiliza stiva st, unde nivelul k al stivei simbolizează ţara k, iar st[k] c
uloarea ataşată ţării k. Stiva are înălţimea n şi pe fiecare nivel ia valori intre 1
şi 4, adică numărul culorilor e maxim 4.
if(st[k]<4){
st[k]++;
return 1;
} else return 0;
}
int Valid(){
int i;