Introducere
Consideram o mulțime cu A
cu n
elemente. Prin combinări de k
elemente din A
înțelegem submulțimile cu k
elemente ale multimii A
. Numărul acestor combinări este
Acest articol prezintă un algoritm backtracking pentru determinarea în ordine lexicografică a combinărilor de k
elemente ale mulțimii A={1 , 2 , ... , n}
, elemente dintr-o combinare fiind generate în ordine crescătoare. El poate fi adaptat pentru determinarea combinărilor de k
elemente ale unei mulțimi oarecare de n
elemente.
Deoarece în algoritmul recursiv general apare funcția Back()
cu parametrul k
, pentru a păstra notațiile din algoritm vom considera în continuare combinările de k
elemente luate câte p
.
Soluția 1
Condiții
Ca orice rezolvare cu algoritmul backtracking, începem prin a preciza semnificația vectorului soluție. Astfel, x[]
reprezintă o combinare. În consecință, el va respecta următoarele condiții:
- elemenele vectorului sunt valori între
1
șin
; - elementele nu se repetă;
- elementele sunt ordonate crescător
- vectorul se completează element cu element. Când va avea
p
elemente, reprezintă o combinare completă, care urmează a fi afișată.
Formal, exprimăm proprietățile de mai sus astfel:
- condiții externe:
; - condiții interne:
, pentru , pentru
- condiții de existență a soluției:
x[k]
(cel care este verificat) și elementele deja generate (x[1]
, x[2]
, … , x[k-1]
).OK()
.Sursa C++
using namespace std; int x[10] , n , p; void Afis(int k) { for(int j = 1 ; j <= k ; j ++) cout << x[j] << " "; cout << endl; } bool OK(int k){ for(int i = 1 ; i < k ; ++ i) if(x[k] == x[i]) return false; if(k > 1) if(x[k] <= x[k-1]) return false; return true; } bool Solutie(int k) { return k == p; } void back(int k){ for(int i = 1 ; i <= n ; ++ i) { x[k] = i; if(OK(k)) if(Solutie(k)) Afis(k); else back(k + 1); } } int main(){ cin >> n >> p; back(1); return 0; }
Soluția 2
Rafinarea condițiilor
Condițiile de mai sus pot fi îmbunătățite, făcând următoarele observații:
- cele două condiții interne pot fi reduse la una singură. Dacă pentru fiecare
are loc relația atunci are loc și condiția ;
Condițiile devin:- condiții externe:
; - condiții interne:
, pentru - condiții de existență a soluției:
- condiții externe:
- condiția internă poate fi transformată în condiție externă. Dacă
atunci valorile pe care le poate lua (condiții externe) sunt . Condițiile devin:- condiții externe:
; - condiții interne: nu există
- condiții de existență a soluției:
- condiții externe:
Cazul x[ 0 ] = 0
, înaintea începerii generării.
Sursă C++
using namespace std; int x[10] , n , p; void Afis(int k) { for(int j = 1 ; j <= k ; j ++) cout << x[j] << " "; cout << endl; } void back(int k){ for(int i = x[k-1] + 1 ; i <= n ; ++ i) { x[k] = i; if(k == p) Afis(k); else back(k + 1); } } int main(){ cin >> n >> p; x[0] = 0; back(1); return 0; }
Probleme
#combinari
nu există sau nu poate fi afișată.
#combinari2
nu există sau nu poate fi afișată.
#siruri
nu există sau nu poate fi afișată.
#SubmDiv
nu există sau nu poate fi afișată.
#cifre_c
nu există sau nu poate fi afișată.
#subimp2
nu există sau nu poate fi afișată.