Sunteți pe pagina 1din 8

FIŞĂ DE LUCRU –CLASA A XI-A

METODA DE PROGRAMARE BACKTRAKING


Produs cartezian, permutări, aranjamente, combinări, submulţimi

Implementare backtraking pentru produs cartezian

Enunţ: Să se genereze toate elementele produsului cartezian A 1, A2,..., An unde


Ai={ 1, 2, ...., n};
void tipar ( )
#include<iostream.h> { for( i=1; i<=n; i++)
using namespace std; cout<<st[i]<<” “;
int n,st[100],k,i; cout<<endl;}
void init( ) void back( )
{ st[k]=0;} { int as, ev;
int successor( ) k=1; init( );
{ if (st[k]<n) { st[k]++; return 1;} while ( k>0)
else return 0;} { as=1; ev=0;
int valid( ) while (as && ! ev)
{ return 1;} { as= successor();
int solutie( ) if (as) ev = valid( );}
{ return k==n;} if(as) if (solutie( )) tipar( );
else {k++; init( );}
else k --;}}
int main( )
{cout<<”n=”; cin >>n;
back( ) ;}

1. Modificaţi algoritmul de mai sus astfel încât să obţineţi toate elementele produsului cartezian A 1, A2,..., An
unde A i={ 1, 2, ....,n i}.
Indicaţie: Numărul de elemente ale fiecărei mulţimi Ai va fi memorat într-un vector m, cu
lungimea logică n, unde m[i]=ni;

2. Scrieţi programul care generează toate “cuvintele” cu patru litere care au prima şi ultima literă vocale, litera a
doua consoană din mulţimea {P,R,S,T}, iar a treia literă consoană din mulţimea { B, M, R, T, V}
Exerciţiu: Generaţi primele 16 soluţii ale acestui produs cartezian. Ce urmează după
soluţiile:IRRU,ESTO;UTVU;OPMU ?

3. Într-un restaurant, un meniu este format din trei feluri de mâncare. Există patru preparate culinare pentru
felul unu , cinci preparate culinare pentru felul doi şi trei preparate culinare pentru felul trei. Să se genereze
toate meniurile care se pot forma cu aceste preparate culinare.

1
FIŞĂ DE LUCRU –CLASA A XI-A
METODA DE PROGRAMARE BACKTRAKING
Produs cartezian, permutări, aranjamente, combinări, submulţimi

2
FIŞĂ DE LUCRU –CLASA A XI-A
METODA DE PROGRAMARE BACKTRAKING
Produs cartezian, permutări, aranjamente, combinări, submulţimi

Implementare backtraking pentru permutări

Enunţ: Să se genereze toate permutările mulţimii A={ 1, 2, ...., n};


Observaţie: în stivă elementele trebuie să fie distincte
În total sunt : n! soluţii
void tipar ( )
#include<iostream>
{ for( i=1; i<=k; i++)
using namespace std;
cout<<st[i]<<” “;
int n,st[100],I,k ;
cout<<endl;}
void init( )
void back( )
{ st[k]=0;}
{ int as, ev;
k=1; init( );
int succesor( )
while ( k>0)
{ if (st[k]<n) { st[k]++; return 1;}
{ as=1;ev=0;
else return 0;}
while (as && ! ev)
{ as= succesor();
int valid( ) // modificare
if (as) ev = valid( );}
{ for( i=1; i<k; i++)
if(as) if (solutie( )) tipar( );
if (st[k] = =st[i]) return 0;
else {k++; init( );}
return 1;}
else k --;} }
int solutie( )
int main( )
{ return k==n;}
{cout<<”n=”; cin >>n;
back( ) ;
return 1;}

Un exemplu de aplicare: Să se genereze toate permutările mulţimii A={ 1, 2, ...., n} în care nu


apar numere consecutive.
Această problemă face parte din clasa de probleme de generare a permutărilor cu condiţie-
soluţia conţine o condiţie internă suplimentară faţă de cea impusă de permutare. In acest caz,
condiţia suplimentară de continuare a construirii soluţiei este ca numărul ales pentru nivelul k al
soluţiei să nu difere printr-o unitate de numărul care se găseşte pe nivelul k-1 al soluţiei.
Modificarea apare în subprogramul valid( ):

int valid( )
{ if ( k>1 && abs(st[k] – st[k-1]) = =1) return 0;
for( i=1; i<k; i++)
if (st[k] = =st[i]) return 0;
return 1;}

Aplicaţii:
1. Să se genereze toate permutările mulţimii A={ 1, 2, ...., n} , în care două numere vecine
nu trebuie să fie ambele pare sau ambele impare.

3
FIŞĂ DE LUCRU –CLASA A XI-A
METODA DE PROGRAMARE BACKTRAKING
Produs cartezian, permutări, aranjamente, combinări, submulţimi

2. Să se genereze toate permutările unei mulţimi de numere oarecare , astfel încât cea mai
mică şi cea mai mare valoare să-şi păstreze poziţiile iniţiale.

Implementare backtracking pentru aranjamente


Enunţ: Să se genereze toate aranjamentele de m elemente multimii A={ 1, 2, ...., n};
Observaţie: în stivă elementele trebuie să fie distincte şi nivelul stivei să fie m. Exemplu de
soluţii( nu nepărat în ordinea generării) pentru mulţimea { 1, 2, 3, 4} aranjamente de 4 luate

câte 3: 123, 134, 234, 321,412 etc. În total sunt : soluţii .

void tipar ( )
#include<iostream> { for( i=1; i<=m; i++)
using namespace std; cout<<st[i]<<” “;
int n,st[100],i; cout<<endl;}
void init( ) void back( )
{ st[k]=0;} { int as, ev;
int succesor( ) k=1; init( );
while ( k>0)
{ if (st[k]<n) { st[k]++; return 1;}
{ as=1; ev=0;
else return 0;} while (as && ! ev)
int valid( ) // modificare { as= succesor();
{ for( i=1; i<k; i++) if (as) ev = valid( );}
if (st[k] = =st[i]) return 0; if(as) if (solutie( )) tipar( );
return 1;} else {k++; init( );}
int solutie( ) // modificare else k --;} }
{ return k==m;} int main( )
{ cin >>n >>m;
back( ) ;}

Un exemplu de aplicare: Să se genereze toate drapelele cu trei culori care se pot forma cu şase
culori: alb,galben, roşu, verde, albastru şi negru- care au în mijloc culoarea alb, verde sau roşu.
Indicaţie : Soluţia are 3 elemente, un elemente al soluţiei fiind indicele din vector al unei culori.
Se generează aranjamente cu condiţia de 6 obiecte luate câte 3- soluţia conţine o condiţie internă
suplimentară faţă de cea impusă de aranjamente: elementul 2 al soluţiei să fie indicele culorii alb,
verde sau roşu.

int valid(
{ if (k==2 && (st[k]== 2 || st[k] == 5 || st[k]= =6 )) return 0; Atenţie: mai sunt şi alte
for( i=1; i<k; i++) modificări de făcut în
if (st[k] = =st[i]) return 0; algoritm!!!!!!!!!!!!!
return 1;}

Aplicaţii:
1. Se citesc de la tastatură n cifre distincte. Să se genereze toate numerele de m cifre
( m<=n) care se pot forma cu aceste cifre şi care conţin toate cele n cifre.

4
FIŞĂ DE LUCRU –CLASA A XI-A
METODA DE PROGRAMARE BACKTRAKING
Produs cartezian, permutări, aranjamente, combinări, submulţimi

2. Să se genereze toate anagramele unui cuvânt , din care se elimină p litere oarecare .
Valoarea minimă a numărului p este 1, iar valoarea maximă este cu 1 mai mică decât
lungimea cuvântului. Se citesc de la tastatură literele cuvântului şi valoarea numărului p.

Implementare backtracking pentru combinări


Enunţ: Să se genereze toate combinările de m elemente ale multimii A={ 1, 2, ...., n};
Observaţie: nivelul stivei să fie m şi soluţiile obţinute să fie distincte, adică două soluţii să nu conţină
aceleaşi numere. Pentru aceasta , se va adăuga o condiţie de continuare suplimentară: valoarea de pe
nivelul k trebuie să fie strict mai mare decăt oricare dintre valorile de pe nivelele inferioare. Condiţia
de continuare este îndeplinită dacă elementul de pe nivelul k va avea o valoare strict mai mare decât
valoarea elementului de pe nivelul k-1( se iniţializează cu o valoare egală cu cea a elemtului de pe nivelul
k-1) şi o valoare mai mică decât n-m+k( se caută succesorul până la valoarea n-m+k)
Exemplu de soluţii pentru mulţimea { 1, 2, 3, 4} combinări de 4 luate câte 3: 123,124, 134, 234.

În total sunt : soluţii . void tipar ( ) // modificare


{ for( i=1; i<=m; i++)
cout<<st[i]<<” “;
#include<iostream> cout<<endl;}
using namespace std; void back( )
int n,st[100],i; { int as, ev;
void init( ) // modificare k=1; init( );
{ if (k= =1) st[k]=0; while ( k>0)
else st[k]=st[k-1];} { as=1, ev=0;
int successor( ) // modificare while (as && ! ev)
{ if (st[k]<n-m+k) { as= successor();
{ st[k]= st[k]+1; return 1;} if (as) ev = valid( );}
else return 0;} if(as) if (solutie( )) tipar( );
int valid( ) else {k++; init( );}
{ return 1;} else k --;} }
int solutie( ) // modificare int main( )
{ return k==m;} {cout<<”n=”; cin >>n; back( ) ;}

Algoritmul de generare a combinărilor poate fi folosit în problemele de generare a tuturor posibilităţilor de a


forma- din n obiecte-grupuri de m obiecte, care să aibă anumite proprietăţi.
Un exemplu de aplicare: din n obiecte trebuie să se distribuie unei persoane m obiecte care să conţină
obligatoriu obiectul p şi să nu conţină obiectul q. Să se genereze toate posibilităţile de a forma grupuri de m
astfel de obiecte. Pentru simplificare vom considera mulţimea obiectelor ca fiind {1, 2, 3, ...., n}.Valorile
pentru numărul de obiecte , n, numărul de obiecte din grup,m, şi indicii obiectelor p şi q- se citesc de la
tastatură.
Deoarece obiectul p face parte obligatoriu din grupul de obiecte, el va fi memorat ca prim element al soluţiei
( în main se scrie st[1]= p), iar subprogramul back( ) va genera numai următoarele m-1 elemente ale
soluţiei( k va porni de la 2 şi condiţia de continuare va fi k>1). Se modifică şi condiţia de continuare a
construirii soluţiei( subprogramul valid( ) , deoarece obiectele p şi q nu pot fi elemente ale soluţiei).
int valid( )
{ return st[k]!=p && st[k]!=q ;}

Aplicaţii:
1. Să se genereze toate grupurile de p persoane, care se pot forma din n persoane.
Informaţiile se citesc dintr-un fişier text unde, pe primul rând, sunt scrise valorile pentru p

5
FIŞĂ DE LUCRU –CLASA A XI-A
METODA DE PROGRAMARE BACKTRAKING
Produs cartezian, permutări, aranjamente, combinări, submulţimi

şi n, despărţite printr-un spaţiu, iar pe următoarele rânduri, numele persoanelor, câte un


nume pe un rând.
2. Două persoane îşi împart n obiecte. Fiecare obiect are o valoare vi . Să se genereze
toate posibilităţile de distribuire a celor n obiecte, între cele două persoane, astfel încât
fiecare persoană să primească obiecte care să aibă aceeaşi valoare totală.

Implementare backtracking pentru generarea submul ţimilor unei mulţimi


O submulţime este formată din elemente ale mulţimii A. Pentru simplificarea algoritmului , vom
considera mulţimea A={ 1, 2, ...., n} .
Exemplu A={1, 2, 3} submulţimile acestei mulţimi sunt: Considerăm că un element al mulţimii A
este ales dacă pe poziţia lui punem în
Submulţimi { }= {1} {2} {3} {1, 2} {1,3} {2,3} {1,2,3} stivă valoarea 1, şi neales când în stivă
Stiva 000 100 010 001 110 101 011 111 avem valoarea 0.

Ordinea soluţiilor va fi: 000; 001; 010; 011; 100; 101;110;111


În total sunt 2n submulţimi, unde n este numărul de elemente al mulţimii date.

#include<iostream> void tipar ( ) // modificare


using namespace std; { int x=0; // x numără câte elemente nenule are submulţimea
int n,st[100],i; for( i=1; i<=n; i++)
void init( ) if (st[i]==1) {cout<<v[i]<<” “;
// v este vectorul în care sunt memorate valorile mulţimii
{ st[k]= -1;} // modificare
x++;}
int successor( ) // modificare
{ if (st[k]<1) { st[k]++; return 1;} if(x==0) cout<<” mulţimea vidă”;
else return 0;} cout<<endl;}
int valid( ) void back( )
{ return 1;} { int as, ev;
int solutie( ) k=1; init( );
{ return k==n;} while ( k>0)
{ as=1, ev=0;
while (as && ! ev)
{ as= successor();
if (as) ev = valid( );}
if(as) if (solutie( )) tipar( );
else {k++; init( );}
else k --;}}
int main( )
{cout<<”n=”; cin >>n;
for( i=1; i<=n; i++)
cin>>v[i] ; //elementele mulţimii
back( ) ;}

Un exemplu de aplicare: Să se genereze toate numerele scrise în baza 10 a căror reprezentare


în baza 2 are m cifre, cu condiţia ca două cifre binare alăturate să nu fie amândouă 0.
Exemplu pentru m=4 avem: 10102 =1010 ; 10112 =1110 ;11012 =1310 ; 11102 =1410; 11112 = 1510
(ar mai fi fost şi soluţiile 1000,1001, 1100)
Vom pune o condiţie în funcţia valid( )- care nu va permite să se aşeze în stivă pe poziţii
succesive doi de zero.
int valid( )
{ if ( k>1)
if (st[k-1]*st[k]= =0) return 0;

6
FIŞĂ DE LUCRU –CLASA A XI-A
METODA DE PROGRAMARE BACKTRAKING
Produs cartezian, permutări, aranjamente, combinări, submulţimi

return 1;}

Aplicaţii:
1. Se citesc numele a 6 elevi. Afişaţi toate submulţimile celor 6 elevi.
2. Să se afişeze toate numerele scrise în baza 10 a căror reprezentare în baza 2 are n cifre,
dintre care exact k sunt egale cu 1. Valorile n şi k se citesc de la tastatură( n<12, k<n).
De exemplu, pentru n=3 şi k=2, se obţin valorile: 5 şi 6.

7
FIŞĂ DE LUCRU –CLASA A XI-A
METODA DE PROGRAMARE BACKTRAKING
Produs cartezian, permutări, aranjamente, combinări, submulţimi

Funcția back recursivă


//produsul cartezian a n multimi A={1,2,3,...,n}

#include <iostream>
using namespace std;

int n,st[100],k,i;

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 )
{ return 1;}

int solutie( int k)


{ return k==n+1;}

void tipar ( int k )


{ for( i=1; i<=n; i++)
cout<<st[i]<<" ";
cout<<endl;}

void back(int k )
{ if(solutie(k))tipar(k);
else
{ init(k);
while(successor(k))
if(valid(k))
back(k+1);}
}
int main()
{ cin>>n;
bak(1);
return 0; }

S-ar putea să vă placă și