Documente Academic
Documente Profesional
Documente Cultură
Exemplu:
Sa consideram problema submultimilor de suma data care consta in urmatoarele:
Fie A = (a1, a2, ..., an) cu ai > 0, oricare ar fi i. Fie M inclus in R. Se cauta toate submultimile B ale
lui A pentru care suma elementelor este M.
Pentru a putea realiza problema prin metoda backtracking vom reprezenta solutia sub forma x = (x1,
..., xn) unde xi = 1 daca ai inclus in B si xi = 0 in caz contrar. Sa ne situam in ipoteza ca n = 4.
Castigul obtinut prin introducerea conditiilor de continuare consta in faptul ca, daca intr-un varf ele
nu mai sunt verificate, se va renunta la parcurgerea subarborelui care are ca radacina acest varf.
Acest exemplu permite prezentarea unei variante a metodei backtracking. Intr-adevar, sa
consideram drept solutie posibila o valoare k <= n impreuna cu cuplul (x1, ...,xk) unde pentru i
inclus in {1, ..., k}, xi reprezinta indicele elementului pe care il introducem in B. Evident xi este
diferit de xj pentru i diferit de j. Pentru a nu se repeta solutii, vom presupune x1 < x2 < ... < xn.
Diferite variante ale metodei backtracking nu schimba esenta ei care consta in faptul ca este
reprezentabila pe un arbore care este parcurs "coborand" in arbore numai daca exista sanse de a
ajunge la o solutie rezultat.
In continuare, problemele care vor fi prezentate vor urma o schema generala si anume:
1
- se va testa daca am obtinut o solutie, situatie in care aceasta se va retine;
- daca nu am obtinut o solutie se incearca plasarea unui nou element in vectorul solutie cu
respectarea conditiilor de continuare.
- daca nu se reuseste plasarea unui nou element si spatiul valorilor posibile de plasat s-a epuizat, se
revine la pozitia anterioara si se incearca sa se plaseze pe ea un alt element.
Faptul ca dupa plasarea unui element in vectorul solutie algoritmul presupune plasarea unui element
pe pozitia imediat urmatoare, adica de fapt reluarea algoritmului, conduce posibilitatea abordarii
recursive a algoritmilor de tip backtracking. Acest lucru permite o scriere mult mai scurta si mai
simpla a algoritmilor si apoi a programelor care ii implementeaza. Astfel, general, un algoritm
backtracking poate fi prezentat astfel:
In functie de problema concreta, in algoritmul descris mai sus se vor modifica doar instructiunea
pentru, conditiile interne si cele de solutie, structura algoritmului pastrandu-se.
Problemele care se rezolva prin metoda backtracking pot fi impartite in mai multe grupuri de
probleme cu rezolvari asemanatoare, in functie de modificarile pe care le vom face in algoritm. a)
Probleme in care vectorul solutie are lungime fixa si fiecare element apare o singura data in solutie;
b) Probleme in care vectorul solutie are lungime variabila si fiecare element poate sa apara de mai
multe ori in solutie;
c) Probleme in plan, atunci cand spatiul in care ne deplasam este un tablou bidimensional.
Vom prezenta in cele ce urmeaza cateva probleme care fac parte din primul grup. Cele mai
cunoscute sunt:
- generarea permutarilor unei multimi;
- generarea aranjamentelor unei multimi;
- generarea submultimilor unei multimi;
- generarea submultimilor cu m elemente ale unei multimi (combinari);
- generarea produsului cartezian a n multimi;
- generarea tuturor secventelor de n (par) paranteze care se inchid corect;
- colorarea tarilor de pe o harta astfel incat oricare din doua tari vecine sa aiba culori diferite;
- aranjarea a n regine pe o tabla de sah de dimensiune n fara ca ele sa se atace.
Toate problemele din acest grup au particularitatea ca solutia se obtine atunci cand vectorul solutie
ajunge sa contina un anumit numar de elemente.
Partitiile unui numar natural. Fie n > 0, natural. Sa se scrie un program care sa afiseze toate
partitiile unui numar natural n.
Numim partitie a unui numar natural nenul n o multime de numere naturale nenule {p1, p2, ..., pk}
care indeplinesc conditia p1 + p2 + ... + pk = n.
2
Ex: pt. n = 4 programul va afisa:
4 = 1 + 1 + 1 +1
4=1+1+2
4=2+2
4=4
Observatii:
- lungimea vectorului solutie este cel mult n;
- exista posibilitatea ca solutiile sa se repete;
- conditia de final este indeplinita atunci cand suma elementelor vectorului solutie este n.
Am mentionat mai sus ca vom folosi doi parametri, unul pentru pozitia in vectorul solutie si un al
doilea, in care avem sumele partiale la fiecare moment. Avem determinata o solutie atunci cand
valoarea celui de-al doilea parametru este egala cu n.
In aceasta situatie la fiecare plasare a unei valori in vectorul sol valoarea celui de al doilea parametru
se mareste cu elementul ce se plaseaza in vectorul solutie. Apelul procedurii back din programul
principal va fi back(1, 0).
Exista si posibilitatea de a apela procedura back din programul principal back(1, n) si valoarea celui
de al doilea parametru se decrementeaza cu elementul ce se plaseaza in vectorul sol, iar o solutie
avem cand acest parametru este zero. Indiferent care modalitate este aleasa acest al doilea parametru
ne permite sa optimizam putin programul in sensul ca putem considera niste conditii de continuare
mai stranse.
#include <stdio.h>
#include <conio.h>
int n, ns, sol[20];
void afis(int l)
{int i;
ns++;
printf("\nSolutia nr. %d:\n", ns);
for(i=1; i <= l; i++) printf("%d ", sol[i]);
printf("\n");
}
void back(int i, int sp)
{int j;
if(sp==n)
afis(i-1);
else
for(j=1; j <= n-sp; j++)
if(j >= sol[i-1])
{sol[i]=j;
back(i+1, sp+j);
}
}
int main( void )
{printf("n = "); scanf("%d", &n);
back(1, 0);
printf("\n\n%d solutii!\n\n", ns);
printf("Apasa o tasta pentru a inchide..."); getch();
return 0;
}