Metoda Backtraking
Blogul nostru vă oferă o multitudine de informații, aplicații și teste pentru înțelegerea Metodei Backtraking.
joi, 27 martie 2014
joi, 20 martie 2014
Probleme propuse Metoda Backtracking
1. Se citesc de la tastatura două numere naturale n si p (0<p<n<20).
Să se genereze toate grupările (aranjamentele) de p elemente
distincte ale mulțimii {1,2,3,....n}, grupări care diferă fie prin
valorile elementelor, fie prin ordinea lor (Aranjamente de n luate
câte p).
Să se genereze toate grupările (aranjamentele) de p elemente
distincte ale mulțimii {1,2,3,....n}, grupări care diferă fie prin
valorile elementelor, fie prin ordinea lor (Aranjamente de n luate
câte p).
2. Se citește un număr natural n (n<100). Să se afișeze toate posibilitățile
de scriere a numărului n ca suma de numere naturale mai mici sau egale cu
n (partițiile unui număr).
de scriere a numărului n ca suma de numere naturale mai mici sau egale cu
n (partițiile unui număr).
3. Se citesc de la tastatura doua numere naturale nenule n si S (0<n<10,
0<S<70). Sa se genereze toate numerele formate din n cifre distincte
cu proprietatea ca suma cifrelor este egala S.
cu proprietatea ca suma cifrelor este egala S.
4. Sa se genereze toate numerele de n cifre (0<n<9), formate doar din cifre
pare, cifre aflate in ordine crescatoare.
pare, cifre aflate in ordine crescatoare.
5. Într-o mare închisa sunt n porturi. Staționarea într-un port se taxeaza
printr-un cost c. Sa se stabileasca toate voiajele prin p porturi care să
nu depașească un cost de staționare dat L.
printr-un cost c. Sa se stabileasca toate voiajele prin p porturi care să
nu depașească un cost de staționare dat L.
6. Pentru un n dat să se genereze toate șirurile de 2*n+1 termeni nenegativi
cu proprietatea că x[1]=0, x[2*n+1]=0 si |x[i]-x[i+1]|=1(1<=i<=2*n) .
cu proprietatea că x[1]=0, x[2*n+1]=0 si |x[i]-x[i+1]|=1(1<=i<=2*n) .
7. Dându-se 4 cutii și 8 obiecte să se tiparească toate posibilitățile de repartizare a elementelor în cutii a.î. să fie indeplinite condițiile:
-în cutia 1 se află 1 obiect
-în cutia 2 se află 1 sau 2 obiecte
-în cutia 3 se află 2 sau 3 obiecte
-în cutia 4 se află 3 obiecte
-în cutia 1 se află 1 obiect
-în cutia 2 se află 1 sau 2 obiecte
-în cutia 3 se află 2 sau 3 obiecte
-în cutia 4 se află 3 obiecte
exercitiu rezolvat Metoda Backtracking
Plata unei sume de bani
ENUNT : Avand la dispozitie n saculeti cu monede S1, S2, .... Sn,
fiecare saculet Si continand Nri monede de valoare Vi sa se
afiseze toate modalitatil de aplati o suma data S folosind numai
monezi din saculeti
EXEMPLU: Pentru n=3 , Nr=(10,2,5), V=(1,2,5) si S=5 programul va genera
5 * 1 leu
3 * 1 leu + 1 * 2 lei
1 * 1 leu + 2 * 2 lei
1 * 5 lei
SOLUTIE:
I. Solutia x[1]......x[n]. Elementul x[i] va avea ca valoare numarul
de monede care s-au folosit din saculetul i
II. x[k] poate avea ca valoare orice valoare din intervalul [0,Nrk].
III. Valid
- daca k<n --> suma platita pana la acel moment sa nu depaseasca S
- daca k=n --> suma platita sa fie egala cu S
Implementare
#include<iostream>
using namespace std;
char sp[]=" ";
int x[20], n, nrsol=0, nr[20], val[20], sum[20], S;
int Valid(int k)
{sum[k]=sum[k-1]+val[k]*x[k];
if (sum[k]>S) return 0;
if (k==n && sum[k]!=S) return 0;
return 1;
}
void Afisare()
{int i,j;
cout<<sp;
for(i=1;i<=n;i++)
if (x[i]!=0) cout<<x[i]<<"*"<<val[i]<<" lei + ";
cout<<char(8)<<char(8)<<" "<<endl;
nrsol++;
if (nrsol%22==0) cin.get();
}
void Back()
{int k=1, cand;
x[1]=-1;
while (k>0)
{cand=0;
while (cand==0 && x[k]<nr[k])
{x[k]++;
cand=Valid(k);
}
if (cand==0) k--;
else if (k==n) Afisare();
else {k=k+1; x[k]=-1;
}
}
}
int main()
{int i;
cout<<endl<<endl<<sp<<"Plata unei sume de bani"<<endl;
cout<<endl<<sp<<" Numarul tipuri monezi: "; cin>>n;
cout<<sp<<" Dati suma de plata: "; cin>>S;
cout<<endl;
for (i=1;i<=n;i++)
{cout<<sp<<" Valoare moneda tip "<<i<<": "; cin>>val[i];
cout<<sp<<" Numar monezi tip "<<i<<" : "; cin>>nr[i];
}
Back();
cout<<endl<<sp<<"Numar solutii: "<<nrsol;
return 0;
}
ENUNT : Avand la dispozitie n saculeti cu monede S1, S2, .... Sn,
fiecare saculet Si continand Nri monede de valoare Vi sa se
afiseze toate modalitatil de aplati o suma data S folosind numai
monezi din saculeti
EXEMPLU: Pentru n=3 , Nr=(10,2,5), V=(1,2,5) si S=5 programul va genera
5 * 1 leu
3 * 1 leu + 1 * 2 lei
1 * 1 leu + 2 * 2 lei
1 * 5 lei
SOLUTIE:
I. Solutia x[1]......x[n]. Elementul x[i] va avea ca valoare numarul
de monede care s-au folosit din saculetul i
II. x[k] poate avea ca valoare orice valoare din intervalul [0,Nrk].
III. Valid
- daca k<n --> suma platita pana la acel moment sa nu depaseasca S
- daca k=n --> suma platita sa fie egala cu S
Implementare
#include<iostream>
using namespace std;
char sp[]=" ";
int x[20], n, nrsol=0, nr[20], val[20], sum[20], S;
int Valid(int k)
{sum[k]=sum[k-1]+val[k]*x[k];
if (sum[k]>S) return 0;
if (k==n && sum[k]!=S) return 0;
return 1;
}
void Afisare()
{int i,j;
cout<<sp;
for(i=1;i<=n;i++)
if (x[i]!=0) cout<<x[i]<<"*"<<val[i]<<" lei + ";
cout<<char(8)<<char(8)<<" "<<endl;
nrsol++;
if (nrsol%22==0) cin.get();
}
void Back()
{int k=1, cand;
x[1]=-1;
while (k>0)
{cand=0;
while (cand==0 && x[k]<nr[k])
{x[k]++;
cand=Valid(k);
}
if (cand==0) k--;
else if (k==n) Afisare();
else {k=k+1; x[k]=-1;
}
}
}
int main()
{int i;
cout<<endl<<endl<<sp<<"Plata unei sume de bani"<<endl;
cout<<endl<<sp<<" Numarul tipuri monezi: "; cin>>n;
cout<<sp<<" Dati suma de plata: "; cin>>S;
cout<<endl;
for (i=1;i<=n;i++)
{cout<<sp<<" Valoare moneda tip "<<i<<": "; cin>>val[i];
cout<<sp<<" Numar monezi tip "<<i<<" : "; cin>>nr[i];
}
Back();
cout<<endl<<sp<<"Numar solutii: "<<nrsol;
return 0;
}
Generarea partitiilor unei multimi
Generarea partitiilor unei multimi
ENUNT : Fie n numar natural nenul. Scrieti un program de generare a
tuturor partitiilor multimii {1, 2, 3,..., n}.
EXEMPLU: Pentru n=3 programul va genera
{1} {2} {3}
{1} {2,3}
{2} {1,3}
{3} {1,2}
{1,2,3}
SOLUTIE: Prin partitie se intelege o descompunere a multimii initiale
intr-o reuniune de multimi nevide si disjuncte.
Pentru o multime cu n elemente vor exista maxim n multimi in
cadrul unei partitii.
I. Solutia x[1]......x[n]. Fiecare multime din cadrul partitiei va fi
codificata cu numere de la 1 la n. Elementul x[i] va avea ca valoare
numarul asociat multimii din care face parte.
Solutia Codificare
{1,2,3} 1 1 1
{1,2} {3} 1 1 2
{1,3} {2} 1 2 1
{1} {2,3} 1 2 2
{1} {2} {3} 1 2 3
II. x[k] poate avea ca valoare orice valoare din intervalul [1,k]. Dar
cele mai mari doua elemente din cadrul codificarii unei partitii nu
pot sa difere decat printr-o unitate.
III. Valid - nu este necesar
Implementare
#include<iostream>
using namespace std;
char sp[]=" ";
int x[20], n, nrsol=0, max[20], maxim;
int DeterminareMaxim(int k)
{int maxim=0,i;
for(i=1;i<=k;i++)
if (x[i]>maxim) maxim=x[i];
return maxim;
}
void Afisare()
{int i,j;
cout<<sp;
maxim=DeterminareMaxim(n);
for(j=1;j<=maxim;j++)
{cout<<"{";
for(i=1;i<=n;i++)
if (x[i]==j) cout<<i<<" ";
cout<<"} ";
}
cout<<endl;
nrsol++;
if (nrsol%22==0) cin.get();
}
void BackRec(int k)
{int i;
for(i=1;i<=DeterminareMaxim(k-1)+1;i++)
{ x[k]=i;
if (k==n) Afisare();
else BackRec(k+1);
}
}
int main()
{cout<<endl<<endl<<sp<<"Partiile multimii {1,2,3.....,n}"<<endl;
cout<<endl<<sp<<" Dati valoarea lui n: "; cin>>n;
cout<<endl;
BackRec(1);
cout<<endl<<sp<<"Numar solutii: "<<nrsol;
return 0;
}
ENUNT : Fie n numar natural nenul. Scrieti un program de generare a
tuturor partitiilor multimii {1, 2, 3,..., n}.
EXEMPLU: Pentru n=3 programul va genera
{1} {2} {3}
{1} {2,3}
{2} {1,3}
{3} {1,2}
{1,2,3}
SOLUTIE: Prin partitie se intelege o descompunere a multimii initiale
intr-o reuniune de multimi nevide si disjuncte.
Pentru o multime cu n elemente vor exista maxim n multimi in
cadrul unei partitii.
I. Solutia x[1]......x[n]. Fiecare multime din cadrul partitiei va fi
codificata cu numere de la 1 la n. Elementul x[i] va avea ca valoare
numarul asociat multimii din care face parte.
Solutia Codificare
{1,2,3} 1 1 1
{1,2} {3} 1 1 2
{1,3} {2} 1 2 1
{1} {2,3} 1 2 2
{1} {2} {3} 1 2 3
II. x[k] poate avea ca valoare orice valoare din intervalul [1,k]. Dar
cele mai mari doua elemente din cadrul codificarii unei partitii nu
pot sa difere decat printr-o unitate.
III. Valid - nu este necesar
Implementare
#include<iostream>
using namespace std;
char sp[]=" ";
int x[20], n, nrsol=0, max[20], maxim;
int DeterminareMaxim(int k)
{int maxim=0,i;
for(i=1;i<=k;i++)
if (x[i]>maxim) maxim=x[i];
return maxim;
}
void Afisare()
{int i,j;
cout<<sp;
maxim=DeterminareMaxim(n);
for(j=1;j<=maxim;j++)
{cout<<"{";
for(i=1;i<=n;i++)
if (x[i]==j) cout<<i<<" ";
cout<<"} ";
}
cout<<endl;
nrsol++;
if (nrsol%22==0) cin.get();
}
void BackRec(int k)
{int i;
for(i=1;i<=DeterminareMaxim(k-1)+1;i++)
{ x[k]=i;
if (k==n) Afisare();
else BackRec(k+1);
}
}
int main()
{cout<<endl<<endl<<sp<<"Partiile multimii {1,2,3.....,n}"<<endl;
cout<<endl<<sp<<" Dati valoarea lui n: "; cin>>n;
cout<<endl;
BackRec(1);
cout<<endl<<sp<<"Numar solutii: "<<nrsol;
return 0;
}
Aplicatii Metoda Backtracking
PRODUS CARTEZIAN
Se dau n mulţimi, ca cele de mai jos:
S1={1,2,3,...,w1}
S2={1,2,3,...,w2}
.........................
Sn={1,2,3,...,wn}
Se cere să se gnereze produsul lor cartezian.
Exemplu: pemtru n=3 şi urmăroarele mulţimi
S1={1,2} w1=2
S2={1,2,3} w2=3
S3={1,2} w3=2
produsul cartezian este:
S1 xS2 xS3 ={ (1,1,1),(1,1,2),(1,2,1),(1,2,2),(1,3,1),(1,3,2), (2,2,1),(2,1,2),(2,2,1),(2,2,2),(2,3,1),(2,3,2)}
Prin urmare o soluţie este un şir de n elemente, fiecare element iєSi, cu i=1,n
Să analizăm exemplul de mai sus:
1. La pasul k selectăm un element din mulţimea Sk ={1,2,3,...,wk}.
2. Elementele unei soluţii a produsului cartezian, pot să se repete, pot fi în orice ordine, iar valori străine nu pot apare, deoarece le selectăm doar dintre elementele mulţimii Sk . Prin urmare nu trebuie să impunem condiţii de continuare.
3. Obţinem o soluţie în momentul în care am completat n elemente în vectorul v. Vom memora numărul de elemente al fiecăerei mulţimi Sk , într-un vector w. Soluţiile le vom construi pe rând în vectorul v
Se dau n mulţimi, ca cele de mai jos:
S1={1,2,3,...,w1}
S2={1,2,3,...,w2}
.........................
Sn={1,2,3,...,wn}
Se cere să se gnereze produsul lor cartezian.
Exemplu: pemtru n=3 şi urmăroarele mulţimi
S1={1,2} w1=2
S2={1,2,3} w2=3
S3={1,2} w3=2
produsul cartezian este:
S1 xS2 xS3 ={ (1,1,1),(1,1,2),(1,2,1),(1,2,2),(1,3,1),(1,3,2), (2,2,1),(2,1,2),(2,2,1),(2,2,2),(2,3,1),(2,3,2)}
Prin urmare o soluţie este un şir de n elemente, fiecare element iєSi, cu i=1,n
Să analizăm exemplul de mai sus:
1. La pasul k selectăm un element din mulţimea Sk ={1,2,3,...,wk}.
2. Elementele unei soluţii a produsului cartezian, pot să se repete, pot fi în orice ordine, iar valori străine nu pot apare, deoarece le selectăm doar dintre elementele mulţimii Sk . Prin urmare nu trebuie să impunem condiţii de continuare.
3. Obţinem o soluţie în momentul în care am completat n elemente în vectorul v. Vom memora numărul de elemente al fiecăerei mulţimi Sk , într-un vector w. Soluţiile le vom construi pe rând în vectorul v
vineri, 14 martie 2014
Generarea mulţimilor
A.Generarea produsului cartezian
Se consideră n mulţimi A1, A2, ... , An de forma {1,2..,an}. Să se genereze produsul cartezian al acestor mulţimi.
Am considerat mulţimile de forma {1,2..,an} pentru a simplifica problema, în special la partea de citire si afişare, algoritmul de generare rămânând nemodificat.
Identificăm următoarele particularităţi şi condiţii:
Fiecare element Xk din vectorul soluţie aparţine unei mulţimi {1,2..,ak}. Aici este o diferenţă faţă de algoritmii anteriori în care fiecare element din soluţie era luat din aceeaşi mulţime şi trebuie să avem grijă la acest fapt când scriem programul.
Nu există condiţii între elementele vectorului soluţie.
Obţinem soluţia când s-au generat n valori.
B.Generarea submulţimilor unei mulţimi
Generarea submulţimilor unei mulţimi A cu n elemente se poate face cu ajutorul algoritmului de generare a combinărilor, apelându-l repetat cu valorile 1, 2, ..., n pentru a genera submulţimile cu un element, apoi cele cu două elemente, apoi cu 3 elemente etc.
Această modalitate de rezolvare este şi mai complicată şi mai puţin eficientă decât următoarea, care se bazează pe generarea produsului cartezian {0,1}n. Această a doua metodă este eficientă deoarece generează 2n soluţii, adică exact atâtea câte submulţimi are o mulţime cu n elemente.
Aşadar, generăm toate combinaţiile de lungime n cu valorile 0 şi 1. Pentru fiecare combinaţie parcurgem soluţia X şi afişăm elementele din mulţimea A cărora le corespund valori 1 în X. Astfel, pentru combinaţia 001011 vom afişa elementele de pe poziţiile 3, 5 şi 6 din mulţimea iniţială.
C. Generarea partiţiilor unei mulţimi
Generăm partiţiilor unei mulţimi presupune împărţirea mulţimii în mulţimi nevide şi disjuncte care reunite să dea întreaga mulţime. Putem, ca şi în cazurile anterioare, să considerăm mulţimea {1,2,…,n}. Construim un vector soluţie în care pentru fiecare element vom trece submulţimea în care îl vom include. Această submulţime mai este numită şi clasă.
Algoritmul generează pe rând toate modalităţile de a împărţi elementele mulţimii {1,2,…,n} folosind mai întâi o singură clasă, apoi două, ş.a.m.d. până la n clase.
Se consideră n mulţimi A1, A2, ... , An de forma {1,2..,an}. Să se genereze produsul cartezian al acestor mulţimi.
Am considerat mulţimile de forma {1,2..,an} pentru a simplifica problema, în special la partea de citire si afişare, algoritmul de generare rămânând nemodificat.
Identificăm următoarele particularităţi şi condiţii:
Fiecare element Xk din vectorul soluţie aparţine unei mulţimi {1,2..,ak}. Aici este o diferenţă faţă de algoritmii anteriori în care fiecare element din soluţie era luat din aceeaşi mulţime şi trebuie să avem grijă la acest fapt când scriem programul.
Nu există condiţii între elementele vectorului soluţie.
Obţinem soluţia când s-au generat n valori.
B.Generarea submulţimilor unei mulţimi
Generarea submulţimilor unei mulţimi A cu n elemente se poate face cu ajutorul algoritmului de generare a combinărilor, apelându-l repetat cu valorile 1, 2, ..., n pentru a genera submulţimile cu un element, apoi cele cu două elemente, apoi cu 3 elemente etc.
Această modalitate de rezolvare este şi mai complicată şi mai puţin eficientă decât următoarea, care se bazează pe generarea produsului cartezian {0,1}n. Această a doua metodă este eficientă deoarece generează 2n soluţii, adică exact atâtea câte submulţimi are o mulţime cu n elemente.
Aşadar, generăm toate combinaţiile de lungime n cu valorile 0 şi 1. Pentru fiecare combinaţie parcurgem soluţia X şi afişăm elementele din mulţimea A cărora le corespund valori 1 în X. Astfel, pentru combinaţia 001011 vom afişa elementele de pe poziţiile 3, 5 şi 6 din mulţimea iniţială.
C. Generarea partiţiilor unei mulţimi
Generăm partiţiilor unei mulţimi presupune împărţirea mulţimii în mulţimi nevide şi disjuncte care reunite să dea întreaga mulţime. Putem, ca şi în cazurile anterioare, să considerăm mulţimea {1,2,…,n}. Construim un vector soluţie în care pentru fiecare element vom trece submulţimea în care îl vom include. Această submulţime mai este numită şi clasă.
Algoritmul generează pe rând toate modalităţile de a împărţi elementele mulţimii {1,2,…,n} folosind mai întâi o singură clasă, apoi două, ş.a.m.d. până la n clase.
Generarea aranjamentelor şi a combinărilor
A.Generarea aranjamentelor
Generăm aranjamentele unei mulţimi atunci când ne se cer toate modurile de a alege m elemente distincte dintre cele n ale mulţimii (m<n).
Această problemă se rezolvă foarte uşor folosind metodele de generarea permutărilor. Singurele modificări presupun citirea numărului m, modificarea condiţiei de soluţie, care va fi k=m în loc de k=n şi a numărului de elemente afişate.
B.Generarea combinărilor
Generăm combinărilor unei mulţimi presupune o condiţie suplimentară faţă de permutări sau aranjamente. Acest lucru se datorează faptului că generarea combinărilor presupune alegerea în ordine strict crescătoare a elementelor care compun vectorul soluţie.
Astfel, condiţia de continuare, sau de validare a unui element este aceea că el trebuie să fie strict mai mare decât cel plasat anterior. În acest mod asigurăm faptul că elementele nu se vor repeta şi că vor fi generate în ordine strict crescătoare. Trebuie, însă, să avem grijă să nu punem această condiţie si asupra primului element din vectorul soluţie, deoarece el nu are cu cine să fie comparat.
O optimizare a algoritmului de generare a combinărilor se poate obţine pornind instrucţiunea for pentru plasarea unui element de la valoare următoare valorii generate anterior. Trebuie să avem grijă la prima poziţie, care nu are element anterior. Am putea iniţializa X0 cu 0. Astfel nu mai trebuie să verificăm dacă elementul Xk este mai mare ca Xk-1.
Generăm aranjamentele unei mulţimi atunci când ne se cer toate modurile de a alege m elemente distincte dintre cele n ale mulţimii (m<n).
Această problemă se rezolvă foarte uşor folosind metodele de generarea permutărilor. Singurele modificări presupun citirea numărului m, modificarea condiţiei de soluţie, care va fi k=m în loc de k=n şi a numărului de elemente afişate.
B.Generarea combinărilor
Generăm combinărilor unei mulţimi presupune o condiţie suplimentară faţă de permutări sau aranjamente. Acest lucru se datorează faptului că generarea combinărilor presupune alegerea în ordine strict crescătoare a elementelor care compun vectorul soluţie.
Astfel, condiţia de continuare, sau de validare a unui element este aceea că el trebuie să fie strict mai mare decât cel plasat anterior. În acest mod asigurăm faptul că elementele nu se vor repeta şi că vor fi generate în ordine strict crescătoare. Trebuie, însă, să avem grijă să nu punem această condiţie si asupra primului element din vectorul soluţie, deoarece el nu are cu cine să fie comparat.
O optimizare a algoritmului de generare a combinărilor se poate obţine pornind instrucţiunea for pentru plasarea unui element de la valoare următoare valorii generate anterior. Trebuie să avem grijă la prima poziţie, care nu are element anterior. Am putea iniţializa X0 cu 0. Astfel nu mai trebuie să verificăm dacă elementul Xk este mai mare ca Xk-1.
Abonați-vă la:
Postări (Atom)