Sunteți pe pagina 1din 10

Algoritmi şi programare în C++

Culegere de probleme pentru liceu, clasa a XI - a

Capitolul I. Metoda backtracking


I.1. Probleme rezolvate

1. Fie n un număr natural nenul. Să se genereze permutările de n elemente.


Indicaţii: pentru poziţia curentă k din stivă, se parcurge întreg domeniul de valori {1,2,...,n} şi
după depunerea elementului curent, se verifică dacă valoarea este diferită de toate valorile
depuse anterior.
#include <iostream>
using namespace std;

int n,st[20];
void afiseaza()
{
for (int j=1;j<=n;j++)
cout<<st[j]<<" ";
cout<<"\n";
}
int valid(int k)
{
int sw=1;
for(int j=1;j<k;j++)
if (st[j]==st[k])
sw=0;
return sw;
}
void back(int k)
{
int i;
for(i=1;i<=n;i++)
{
st[k]=i;
if (valid(k))
if (k==n)
afiseaza();
else back(k+1);
}
}
int main()
{
cout<<"n=";cin>>n;
back(1);
return 0;
}

2. Fie n şi m două numere naturale nenule, mn. Să se genereze aranjamentele de n


elemente luate câte m.
Indicaţii: diferenţa faţă de generarea permutărilor constă în condiţia de ieşire din apelul
recursiv, deoarece o soluţie este formată din m elemente.
#include <iostream>
using namespace std;
int n,m,st[20];
void afiseaza()
{
for (int j=1;j<=m;j++)
cout<<st[j]<<" ";

1
Algoritmi şi programare în C++
Culegere de probleme pentru liceu, clasa a XI - a
cout<<"\n";
}
int valid(int k)
{
int sw=1;
for(int j=1;j<k;j++)
if (st[j]==st[k])
sw=0;
return sw;
}
void back(int k)
{ int i;
for(i=1;i<=n;i++)
{
st[k]=i;
if (valid(k))
if (k==m)
afiseaza();
else back(k+1);
}
}
int main()
{
cout<<"n=";cin>>n; cout<<"m=";cin>>m;
back(1);
return 0;
}
3. Fie n şi m două numere naturale nenule, mn. Să se genereze combinările de n
elemente luate câte m.
Indicaţii: diferenţa faţă de generarea aranjamentelor constă în faptul că se generează
elementele în ordine strict crescătoare.
#include <iostream>
using namespace std;
int n,m,st[20];
void afiseaza()
{
for (int j=1;j<=m;j++)
cout<<st[j]<<" ";
cout<<"\n";
}

void back(int k)
{
int i;
for(i=st[k-1]+1;i<=n;i++)
{
st[k]=i;
if (k==m)
afiseaza();
else back(k+1);
}
}
int main()
{
cout<<"n=";cin>>n; cout<<"m=";cin>>m;
back(1);
return 0;
}

2
Algoritmi şi programare în C++
Culegere de probleme pentru liceu, clasa a XI - a
4. Să se genereze toate submulţimile unei mulţimi, ale cărei elemente se introduc de la
tastatură. Se generează toate submulţimile mulţimii {1,2,...,n} în ordine lexicografică, o
soluţie reprezentând indici ai elementelor din mulţimea citită.
#include <iostream>
using namespace std;
int a[100],n,x[100];
void cit(int a[100],int &n)
{
cout<<"\n Introduceti nr de elemente ";cin>>n;
cout<<"\n Introduceti elementele multimii\n";
for (int i=1;i<=n;i++)
{
cout<<"\na["<<i<<"]";
cin>>a[i];
}}
void afis(int x[100],int k)
{
cout<<"\n {";
for (int i=1;i<=k;i++)
cout<<a[x[i]]<<" ";
cout<<"\b}";
}
void back(int k)
{
for(int i=x[k-1]+1;i<=n;i++)
{
x[k]=i;
afis(x,k);
if (k<n)
back(k+1);
}
}
int main()
{
cit(a,n);
back(1);
return 0;
}
5. Să se genereze produsul cartezian al mulţimii {1,2,...,n} cu ea însăşi de m ori.
Indicaţii: deosebirea faţă de generarea aranjamentelor constă în lipsa validării, deoarece în
produsul cartezian elementele se pot repeta.
#include <iostream>
using namespace std;
int n,m,st[20];
void afiseaza()
{
for (int j=1;j<=m;j++)
cout<<st[j]<<" ";
cout<<"\n";
}
void back(int k)
{
int i;
for(i=1;i<=n;i++)
{
st[k]=i;
if (k==m)
afiseaza();
else back(k+1);
}
}
3
Algoritmi şi programare în C++
Culegere de probleme pentru liceu, clasa a XI - a
int main()
{
cout<<"Nr de elemente al multimii=";cin>>n;
cout<<"prod. cartezian de cate ori:";cin>>m;
back(1);
return 0;
}
6. Să se genereze produsul cartezian a n mulţimi având număr diferit de elemente.
Indicaţii: considerăm că elementele mulţimilor sunt numere naturale nenule 1, 2, 3, …
Se foloseşte şirul card care conţine numărul de elemente al celor n mulţimi. Domeniul de
valori pe care le poate lua elementul de pe poziţia k este 1,2,…,card[k].

#include <iostream>
using namespace std;
int n,m,st[20],card[20];
void afiseaza()
{
for (int j=1;j<=n;j++)
cout<<st[j]<<" ";
cout<<"\n";
}
void back(int k)
{
int i;
for(i=1;i<=card[k];i++)
{
st[k]=i;
if (k==n)
afiseaza();
else back(k+1);
}
}
int main()
{
cout<<"Nr. de multimi=";cin>>n;
for(int j=1;j<=n;j++)
{
cout<<"Nr. de elem. al multimii nr "<<j<<":";
cin>>card[j];
}
back(1);
return 0;
}
7. Să se genereze toate funcţiile injective f:{1,2,…,n}--> {1,2,…,m}.
#include <iostream>
using namespace std;
int x[20],n,m;
void scriere()
{
for (int i=1; i<=n; i++)
{
cout <<"f("<<i<<")="<<x[i];
cout <<"\n";
}
cout <<"\n";

}
int valid(int k)
{
for (int i=1;i<k;i++)
if (x[k]==x[i]) return 0;
4
Algoritmi şi programare în C++
Culegere de probleme pentru liceu, clasa a XI - a
return 1;
}
void back(int k)
{
int i;
for (i=1;i<=m;i++)
{ x[k]=i;
if (valid(k))
if (k==n) scriere();
else
back(k+1);
}
}
int main()
{
cout <<"n="; cin >>n; cout <<"m="; cin >>m;
if (m<n) cout <<"Nu exista functii injective.";
else back(1);
return 0;
}

8. Să se genereze toate funcţiile surjective f:{1,2,…,n} -> {1,2,…,m}.


#include <iostream>
using namespace std;
int x[20],m,n;
void afisare()
{
for(int i=1;i<=n;i++)
{
cout <<"f("<<(i)<<")="<<x[i];
cout <<"\n";
}
cout <<"\n";
}
int valid(int k)
{
int sw=1,i,ap[20]={0};
for(i=1;i<=k;i++)
ap[x[i]]=1;
for(i=1;i<=m;i++)
if (ap[i]==0) sw=0;
return sw;
}
void back(int k)
{
for (int i=1;i<=m;i++)
{
x[k]=i;
if(k==n)
{if(valid(k))
afisare();
}
else back(k+1);
}
}
int main()
{
cout <<"n="; cin >>n;
cout <<"m="; cin >>m;
if (m>n) cout <<"Nu exista functii surjective.";

5
Algoritmi şi programare în C++
Culegere de probleme pentru liceu, clasa a XI - a
else back(1);
return 0;
}
9. Să se plaseze n regine pe o tablă de şah de dimensiune nxn astfel încât oricare
două regine să nu se atace. Conform regulilor de şah două regine se atacă dacă sunt pe
aceeaşi linie, coloană sau diagonală.
Indicaţii: se foloseşte un şir care păstrează pe poziţia i, coloana pe care se află regina de pe
linia i, deci nu pot fi două regine pe aceeaşi linie. Neatacul pe coloane se verifică prin faptul
că valoarea depusă în poziţia curentă este diferită de cele anterioare. Pe diagonale, condiţia
ce trebuie îndeplinită este k-i≠| st[k]-st[i] |.
#include <iostream>
#include <math.h>
using namespace std;
int n,st[20],nr_sol;
void afiseaza()
{
nr_sol++;
cout<<"Solutia nr "<<nr_sol<<"\n";
for (int j=1;j<=n;j++)
{
for (int l=1;l<=n;l++)
if (l==st[j])
cout<<"R ";
else cout<<"* ";
cout<<"\n";
}
cout<<"\n";
}
int valid(int k)
{ int sw=1;
for(int j=1;j<k;j++)
{
if (st[j]==st[k]) sw=0;
if(fabs(st[j]-st[k])==k-j) sw=0;
}
return sw;
}
void back(int k)
{int i;
for(i=1;i<=n;i++)
{
st[k]=i;
if (valid(k))
if (k==n)
afiseaza();
else back(k+1);
}
}
int main()
{
cout<<"n=";cin>>n;
back(1);
if (nr_sol==0) cout<<"Nici o solutie!!";
return 0;
}
10. Se citeşte de la tastatură dimensiunea n a unei matrici binare (cu elem. 0 sau 1). Să
se formeze toate matricele posibile astfel incât pe fiecare linie respectiv coloană să fie exact
un element nenul.

6
Algoritmi şi programare în C++
Culegere de probleme pentru liceu, clasa a XI - a
Indicaţii: rezolvarea problemei se reduce, de fapt, la generarea permutărilor de n elemente.
Matricea nu se formează, ci doar se afişează aplicând următoarea regulă: pe linia i se va
scrie "0" pentru toate elementele cu indice de coloană diferit de p(i) şi 1 pe coloana p(i).
#include <iostream>
using namespace std;
int n,st[20];
void afiseaza()
{
for (int j=1;j<=n;j++)
{
for (int l=1;l<=n;l++)
if (l==st[j])
cout<<"1 ";
else cout<<"0 ";
cout<<"\n";
}
cout<<"\n";
}
int valid(int k)
{ int sw=1;
for(int j=1;j<k;j++)
if (st[j]==st[k])
sw=0;
return sw;
}
void back(int k)
{
int i;
for(i=1;i<=n;i++)
{
st[k]=i;
if (valid(k))
if (k==n)
afiseaza();
else back(k+1);
}
}
int main()
{
cout<<"n=";cin>>n;
back(1);
return 0;
}
11. Într-o clasă de n elevi sunt f fete (f<=n). Afişaţi toate echipele care se pot constitui
din m elevi, dintre care p fete (pmn, pf). Numerele n, f, p şi m se citesc de la tastatură.
Soluţiile posibile se afişează în felul următor: mai întâi fetele (f1, f3 etc.) şi apoi băieţii.
Indicaţii: numerotăm fetele de la 1 la f şi băieţii de la f+1 la n şi generăm toate echipele de p
elevi, punând condiţia suplimentară să fie m fete în echipă.

#include <iostream>
using namespace std;
int n,m,p,f,st[20],nr_f;
void afiseaza()
{
for (int j=1;j<=m;j++)
if (st[j]<=f)
cout<<"f"<<st[j]<<" ";
for (int j=1;j<=m;j++)
if (st[j]>f)
cout<<"b"<<st[j]-f<<" ";

7
Algoritmi şi programare în C++
Culegere de probleme pentru liceu, clasa a XI - a
cout<<"\n";
}
void back(int k)
{
int i;
for(i=st[k-1]+1;i<=n;i++)
{
st[k]=i;
if(i<=f) nr_f++;
if (k==m)
{
if (nr_f==p)
afiseaza();
}
else back(k+1);
if(i<=f) nr_f--;
}
}
int main()
{
cout<<"Numarul total de elevi=";cin>>n;
cout<<"Numarul total de fete=";cin>>f;
cout<<"Numarul de elevi din echipe=";cin>>m;
cout<<"Numarul de fete din echipe=";cin>>p;
back(1);
return 0;
}
12. Se dau mărgele de 5 culori: alb, roşu, verde, albastru, negru. Numărul mărgelelor de
fiecare culoare se consideră nelimitat. Să se afişeze toate colierele de n mărgele care se pot
forma, respectând următoarele condiţii:
- nu poate fi plasată o mărgea verde lângă o mărgea albastră;
- nu pot fi plasate mărgele vecine de aceeaşi culoare;
- numărul mărgelelor roşii nu poate depăşi o treime din numărul total de mărgele din colier
Indicaţii: culorile mărgelelor se codifică astfel: alb cu ’a’, albastru cu 'b', roşu cu 'r', verde cu
'v', negru cu 'n'. Algoritmul are la bază generarea elementelor produsului cartezian, însă sunt
necesare validări. A nu se uita că prima mărgea este lângă ultima!
#include <iostream>
using namespace std;
int n,st[50];
char c[6]={' ','a','r','v','b','n'};
int valid(int i,int j)
{
int da=1;
if(st[i]==st[j]) da=0;
if((st[i]==3)&&(st[j]==4)) da=0;
if((st[i]==4)&&(st[j]==3)) da=0;
return da;
}
void afiseaza()
{
int nr_r=0,j;
for ( j=1;j<=n;j++)
if(st[j]==2) nr_r++;
if (nr_r<=n/3)
{
for (j=1;j<=n;j++)
cout<<c[st[j]]<<" ";
cout<<"\n";
}

8
Algoritmi şi programare în C++
Culegere de probleme pentru liceu, clasa a XI - a
}
void back(int k)
{
int i;
for(i=1;i<=5;i++)
{
st[k]=i;
if (valid(k,k-1))
if (k==n)
{
if (valid(n,1))
afiseaza();
}
else back(k+1);
}

}
int main()
{
cout<<"Nr de margele din colier=";cin>>n;
back(1);
return 0;
}
13. Aceeaşi problemă, însă cu cerinţa: să se genereze un singur colier cu condiţiile date.
Indicaţii: deosebirea faţă de generarea tuturor soluţiilor constă în faptul că se iese din
generare dacă există deja o soluţie.
#include <iostream>
using namespace std;
int n,nr_sol,st[50];
char c[6]={' ','a','r','v','b','n'};
int valid(int i,int j)
{
int da=1;
if(st[i]==st[j]) da=0;
if((st[i]==3)&&(st[j]==4)) da=0;
if((st[i]==4)&&(st[j]==3)) da=0;
return da;
}
void afiseaza()
{
int nr_r=0,j;
for ( j=1;j<=n;j++)
if(st[j]==2) nr_r++;
if (nr_r<=n/3)
{ nr_sol++;
for (j=1;j<=n;j++)
cout<<c[st[j]]<<" ";
cout<<"\n";
}
}
void back(int k)
{
int i;
for(i=1;i<=5;i++)
if(nr_sol==0)
{
st[k]=i;
if (valid(k,k-1))
if (k==n)
{
9
Algoritmi şi programare în C++
Culegere de probleme pentru liceu, clasa a XI - a
if (valid(n,1))
afiseaza();
}
else back(k+1);
}

}
int main()
{
cout<<"Nr de margele din colier=";cin>>n;
back(1);
if (nr_sol==0)
cout<<"Problema nu are solutii";
return 0;
}
14. Să se genereze toate şirurile strict crescătoare de lungime m formate din divizori ai
unui număr dat n (0<n, m<1000). Fiecare şir rezultat va fi scris pe câte o linie în fişierul
diviz.txt cu câte un spaţiu între elementele ce-l formează. În cazul în care nu există soluţie,
se va scrie pe ecran mesajul "Fără soluţie".
Indicaţii: se formează şirul divizorilor lui n şi apoi se foloseşte algoritmul de generare al
combinărilor.
#include <iostream>
#include <fstream>
using namespace std;
int n,m,nr,st[20],diviz[20];
ofstream f("DIVIZ.TXT");
void formare()
{
nr=0;
for (int i=1;i<=n/2;i++)
if(!(n%i)) diviz[++nr]=i;
diviz[++nr]=n;
}
void scriere()
{
for (int j=1;j<=m;j++)
f<<diviz[st[j]]<<" ";
f<<"\n";
}
void back(int k)
{
int i;
for(i=st[k-1]+1;i<=nr;i++)
{
st[k]=i;
if (k==m)
scriere();
else back(k+1);
}
}
int main()
{
cout<<"n=";cin>>n; cout<<"m=";cin>>m;
formare();
if(m>nr) cout<<"Fara solutie!";
else
back(1);
f.close();
return 0;
}

10

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