Sunteți pe pagina 1din 30

OLEGIUL NAŢIONAL GEORGE COŞBUC

LUCRARE PENTRU ATESTAREA COMPETENŢELOR PROFESIONALE

PROFESOR COORDONATOR:GIORGESCU EMILIA MIHAELA

ABSOLVENT:SULEA CRISTIAN DAMIAN A CLASA A XII-B

MOTRU-2023

COLEGIUL NAŢIONAL GEORGE COŞBUC

LUCRARE PENTRU ATESTAREA COMPETENŢELOR PROFESIONALE


PROFESOR COORDONATOR:GIORGESCU EMILIA MIHAELA

ABSOLVENT:SULEA CRISTIAN DAMIAN A CLASA A XII-B

MOTRU-2023

CUPRINS:

 1.INTRODUCERE...........................pag.3
 2.BACKTRACKING......................................pag.4
 3.PROGRAME SI PROBLEME......pag.11
 4.BIBLIOGRAFIE...........................pag.30
BACKTRACKING

Metoda backtracking poate fi folosită în rezolvarea a diverse probleme. Este o metodă lentă,
dar de multe ori este singura pe care o avem la dispoziție!
Introducere
Metoda backtracking poate fi aplicată în rezolvarea problemelor care respectă următoarele
condiții:
 soluția poate fi reprezentată printr-un tablou x[]=(x[1], x[2], ..., x[n]), fiecare element
x[i] aparținând unei mulțimi cunoscute Ai;
 fiecare mulțime Ai este finită, iar elementele ei se află într-o relație de ordine
precizată – de multe ori cele n mulțimi sunt identice;
 se cer toate soluțiile problemei sau se cere o anumită soluție care nu poate fi
determinată într-un alt mod (de regulă mai rapid).
Algoritmul de tip backtracking construiește vectorul x[] (numit vector soluție) astfel:
Fiecare pas k, începând (de regulă) de la pasul 1, se prelucrează elementul curent x[k] al
vectorului soluție:
 x[k] primește pe rând valori din mulțimea corespunzătoare Ak;
 la fiecare pas se verifică dacă configurația curentă a vectorului soluție poate duce la o
soluție finală – dacă valoarea lui x[k] este corectă în raport cu x[1], x[2], … x[k-1]:
o dacă valoarea nu este corectă, elementul curent X[k] primește următoarea
valoare din Ak sau revenim la elementul anterior x[k-1], dacă X[k] a primit
toate valorile din Ak – pas înapoi;
o dacă valoarea lui x[k] este corectă (avem o soluție parțială), se verifică
existența unei soluții finale a problemei:
 dacă configurația curentă a vectorului soluție x reprezintă soluție finală
(de regulă) o afișăm;
 dacă nu am identificat o soluție finală trecem la următorul element,
x[k+1], și reluăm procesul pentru acest element – pas înainte.
Pe măsură ce se construiește, vectorul soluție x[] reprezintă o soluție parțială a problemei.
Când vectorul soluție este complet construit, avem o soluție finală a problemei.
Exemplu
Să rezolvăm următoarea problemă folosind metoda backtracking, “cu creionul pe hârtie”: Să
se afișeze permutările mulțimii {1, 2, 3}.
Ne amintim că un șir de numere reprezintă o permutare a unei mulțimi M dacă și numai dacă
conține fiecare element al mulțimii M o singură dată. Altfel spus, în cazul nostru:
 are exact 3 elemente;
 fiecare element este cuprins între 1 și 3;
 elementele nu se repetă.
Pentru a rezolva problemă vom scrie pe rând valori din mulțimea dată și vom verifica la
fiecare pas dacă valorile scrise duc la o permutare corectă:

k x[] Observații

1 1–– corect, pas înainte

2 11– greșit

2 12– corect, pas înainte

3 121 greșit

3 122 greșit

3 123 soluție finală 1

3 12! am terminat valorile


posibile pentru x[ 3 ], pas
înapoi

2 13– corect, pas înainte

3 131 greșit

3 132 soluție finală 2

3 133 greșit

3 13! am terminat valorile


posibile pentru x[ 3 ], pas
înapoi

2 1!– am terminat valorile


posibile pentru x[ 2 ], pas
înapoi

1 2–– corect, pas înainte

2 21– corect, pas înainte

3 211 greșit

3 212 greșit

3 213 soluție finală 3

3 21! am terminat valorile


posibile pentru x[ 3 ], pas
înapoi

2 22– greșit

2 23– corect, pas înainte

3 231 soluție finală 4

3 232 greșit

3 233 greșit

3 23! am terminat valorile


posibile pentru x[ 3 ], pas
înapoi

2 2!– am terminat valorile


posibile pentru x[ 2 ], pas
înapoi

1 3–– corect, pas înainte


2 31– corect, pas înainte

3 311 greșit

3 312 soluție finală 5

3 313 greșit

3 31! am terminat valorile


posibile pentru x[ 3 ], pas
înapoi

2 32– corect, pas înainte

3 321 soluție finală 6

3 322 greșit

3 323 greșit

3 32! am terminat valorile


posibile pentru x[ 3 ], pas
înapoi

2 33– greșit

2 3!– am terminat valorile


posibile pentru x[ 2 ], pas
înapoi

1 !–– am terminat valorile


posibile pentru x[ 1 ], pas
înapoi

Formalizare
Pentru a putea realiza un algoritm backtracking pentru rezolvarea unei probleme trebuie să
răspundem la următoarele întrebări:
1. Ce memorăm în vectorul soluție x[]? Uneori răspunsul este direct; de exemplu, la
generarea permutărilor vectorul soluție reprezintă o permutare a mulțimii
A={1,2,...,n}. În alte situații, vectorul soluție este o reprezentare mai puțin directă a
soluției; de exemplu, generarea submulțimilor unei mulțimi folosind vectori
caracteristici sau Problema reginelor.
2. Ce valori poate lua fiecare element x[k] vectorului soluție și câte elemente poate
avea x[]? Altfel spus, care sunt mulțimile Ak. Vom numi aceste restricții condiții
externe. Cu cât condițiile externe sunt mai restrictive (cu cât mulțimile Ak au mai
puține elemente), cu atât va fi mai rapid algoritmul!
3. Ce condiții trebuie să îndeplinească x[k] ca să fie considerat corect? Elementul
x[k] a primit o anumită valoare, în conformitate ce condițiile externe. Este ea corectă?
Poate conduce la o soluție finală? Aceste condiții se numesc condiții interne și în ele
pot să intervină doar x[k] și elementele x[1], x[2], …, x[k-1]. Elementele x[k+1], …,
x[n] nu poti apărea în condițiile interne deoarece încă nu au fost generate!!!
4. Am găsit o soluție finală? Elementul x[k] a primit o valoare conformă cu condițiile
externe, care respectă condițiile interne. Am ajuns la soluție finală sau continuăm cu
x[k+1]?
Exemplu. Pentru problema generării permutărilor mulțimii A={1,2,3,…,n}�={1,2,3,…,�},
condițiile de mai sus sunt:
5. Vectorul soluție conține o permutare a mulțimii A�;
6. Condiții externe: x[k]∈{1,2,3,…,n}�[�]∈{1,2,3,…,�} sau
x[k]=1,n¯¯¯¯¯¯¯¯�[�]=1,�¯, pentru k=1,n¯¯¯¯¯¯¯¯�=1,�¯
7. Condiții interne: x[k]≠x[i]�[�]≠�[�], pentru
i=1,k−1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯�=1,�−1¯
8. Condiții de existență a soluției: k=n�=�
Algoritmul general
Metoda backtracking poate fi implementată iterativ sau recursiv. În ambele situații se se
folosește o structură de deate de tip stivă. În cazul implementării iterative, stiva trebuie
gestionată intern în algoritm – ceea ce poate duce la dificulăți în implementăre. În cazul
implementării recursive se folosește spațiu de memorie de tip stivă – STACK alocat
programului; implementarea recursivă este de regulă mai scurtă și mai ușor de înțeles. Acest
articol prezintă implementări recursive ale metodei.
Următorul subprogram recursiv prezintă algoritmul la modul general:
 la fiecare apel BACK(k) se generează valori pentru elementul x[k] al vectorului
soluție;
 instrucțiunea Pentru modelează condițiile externe;
 subprogramul OK(k) verifică condițiile interne
 subprogramul Solutie(k) verifică dacă configurația curentă a vectorului soluție
reprezintă o soluție finală
 subprogramul Afisare(k) tratează soluția curentă a problemei – de exemplu o afișează!
subprogram BACK(k)
┌ pentru fiecare element i din A[k] executa
│ x[k] ← i
│ ┌ daca OK(k) atunci
│ │ ┌ daca Solutie(k) atunci
│ │ │ Afisare(k)
│ │ │ altfel
│ │ │ BACK(k+1)
│ │ └■
│ └■
└■
sfarsit_subprogram
Observații:
 de cele mai multe ori mulțimile A sunt de forma A={1,2,3,….,n} sau A={1,2,3,
….,m} sau A={a,a+1,a+2,….,b} sau o altă formă astfel încât să putem scrie
instrucțiunea Pentru conform specificului limbajului de programare folosit – eventual
folosind o structură repetitivă de alt tip! Dacă este necesar, trebuie realizate unele
transformări încât mulțimile să ajungă la această formă!

 elementele mulțimii A� pot fi in orice ordine. Contează însă ordinea în care le vom
parcurge în instrucțiunea Pentru, deoarece în probleme este precizată de obicei o
anumită ordine în care trebuie generate soluțiile:
o dacă parcurgem elementele lui A� în ordine crescătoare vom obține soluții în
ordine lexicografică;
o dacă parcurgem elementele lui A� în ordine descrescătoare vom obține
soluții în ordine invers lexicografică.

 în anumite probleme determinarea unei soluții finale nu conduce la întreruperea


apelurilor recursive. Un exemplu este generarea submulțimilor unei mulțimi. În acest
caz algoritmul de mai sus poate fi modificat astfel:
┌ daca OK(k) atunci
│ ┌ daca Solutie(k) atunci
│ │ Afisare(k)
│ └■
│ BACK(k+1)
└■

Un șablon C++

Următoarea secvență C++ oferă un șablon pentru rezolvarea unei probleme oarecare folosind
metoda backtracking. Vom considera în continuare următoarele condiții externe:
x[k]=A,B¯¯¯¯¯¯¯¯¯¯�[�]=�,�¯, pentru k=1,n¯¯¯¯¯¯¯¯�=1,�¯. În practică A� și
B� vor avea valori specifice problemei:

#include <fstream>
using namespace std;

int x[10] ,n;


int Solutie(int k){
// x[k] verifică condițiile interne
// verificare dacă x[] reprezintă o soluție finală
return 1; // sau 0
}
int OK(int k){
// verificare conditii interne
return 1; // sau 0
}

void Afisare(int k)
{
// afișare/prelucrare soluția finală curentă
}

void Back(int k){


for(int i = A ; i <= B ; ++i)
{
x[k]=i;
if( OK(k) )
if(Solutie(k))
Afisare(k);
else
Back(k+1);
}}
int main(){
//citire date de intrare
Back(1);
return 0;}
De multe ori condițiile de existență a soluției sunt simple și nu se justifică scrierea unei
funcții pentru verificarea lor, ele putând fi verificate direct în funcția Back().
De cele mai multe ori, rezolvarea unei probleme folosind metoda backtracking constă în
următoarele:
9. stabilirea semnificației vectorului soluție;
10. stabilirea condițiilor externe;
11. stabilirea condițiilor interne;
12. stabilirea condițiilor de existența a soluției finale;
13. completarea adecvată a șablonului de mai sus!
Complexitatea algoritmului
Algoritmii Backtracking sunt exponențiali. Complexitatea depinde de la problemă la
problemă dar este de tipul O(an)�(��). De exemplu:
 generarea permutărilor unei mulțimi cu n elemente are complexitatea O(n!)�(�!);
 generarea submulțimilor unei mulțimi cu n elemente are complexitatea O(2n)�(2�)
 produsul cartezian An�� unde mulțimea A={1,2,3,…,m}�={1,2,3,…,�} are
complexitatea O(mn)�(��)
 etc.
PROBLEME

1. Se citesc doua numere naturale n si m (m mai mic decat n). Afisati toate partitiile multimii
{1,2,3, ... , n} care sunt formate din m submultimi.
Exemplu:
n=4
m=3
Se vor afisa partitiile:
{1 2 } {3 } {4 }
{1 3 } {2 } {4 }
{1 } {2 3 } {4 }
{1 4 } {2 } {3 }
{1 } {2 4 } {3 }
{1 } {2 } {3 4 }
Nrsol=14
#include<fstream>
using namespace std;
ifstream f("date.in");
ofstream g("date.out");
int n,m,x[10],nrsol=0;
void afis()
{int i,j,max=0;
max=0;
for(i=1;i<=n;i++)
if(x[i]>max) max=x[i];
if(max==m)
1
{ for(i=1;i<=max;i++)
{ g<<"{";
for(j=1;j<=n;j++)
if(x[j]==i) g<<j<<" ";
g<<"} ";
}
g<<endl; }
nrsol++;}
int bun(int k)
{if(k==1)
if(x[k]==1) return 1;
else return 0;
else
{int max=0;
for(int i=1;i<k;i++) if(x[i]>max) max=x[i];
if(max+1<x[k]) return 0;}
return 1;}
void backrec(int k)
{int i;
for(i=1;i<=m;i++)
{
x[k]=i;
if(bun(k)) if(k==n) afis();
else backrec(k+1);}
}
2
int main()
{ f>>n>>m;
backrec(1);
g<<"Nrsol="<<nrsol;
f.close();
g.close();
return 0;}
2.Hercule trebuie sa strabata un labirint cu capcane reprezentat de o matrice nXn. Pentru
fiecare celula a labirintului, se cunoaste timpul in minute dupa care celula respectiva devine
capcana. Dupa ce o celula devine capcana, Hercule moare daca intra in acea celula.Hercule
porneste din coltul stanga-sus al labirintului si trebuie sa ajunga in coltul dreapta jos. El are
nevoie de un minut ca sa treaca dintr-o celula intr-una vecina si se poate deplasa in sus, in
jos,spre stanga sau spre dreapta.
Sa se afiseze timpul minim in care poate Hercule sa strabata labirintul, numarul de drumuri
de timp minim, precum si toate drumurile minime pe care le poate urma Hercule prin labirint
de la intrare la iesire, astfel incat Hercule sa nu moara. Drumurile vor fi afisate ca matrici in
care sunt indicati pasii lui Hercule.
Hercule.in
66
345678
311119
5 6 7 12 11 10
1 7 1 13 1 1
1 8 1 14 15 16
1 9 10 11 12 17
340000
050000
060000
0 7 8 9 10 11
Nrsol=4
#include <fstream>
using namespace std;
ifstream f("hercule.in");
ofstream g("hercule.out");
const int di[]={-1,0,1,0};
const int dj[]={0,1,0,-1};
int a[100][100], x[100][100], m,n,pmin=10000,nr=0,nrsol=0;
void citire()
{f>>m>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
f>>a[i][j];}
void afis(int x[100][100])
{ for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
g<<x[i][j]<<" ";
g<<endl; }
g<<endl;nrsol++;}
void alege(int pas)//alege minimul si numarul de drumuri de lungime minima
{
if(pas<pmin) { pmin=pas; nr=1;}
else if(pas==pmin) nr++;}
void backrec(int i, int j, int pas)
{
x[i][j]=pas;
if(i==m && j==n) alege(pas);
else
for(int d=0;d<4;d++)
{
int inou=i+di[d];
int jnou=j+dj[d];
if(pas<a[inou][jnou] && x[inou][jnou]==0 && pas<pmin) //inca nu e capcana, e pozitie
noua si nu s-a depasit nr min de pasi
backrec(inou,jnou,pas+1);}
x[i][j]=0;}
void backmin(int i, int j, int pas) //face doar drumurile de lungime minima
{ x[i][j]=pas;
if(i==m && j==n && pas==pmin) afis(x);
else
for(int d=0;d<4;d++)
{int inou=i+di[d];
int jnou=j+dj[d];
if(pas<a[inou][jnou] && x[inou][jnou]==0 && pas<pmin)
backmin(inou,jnou,pas+1); }
x[i][j]=0;}
int main()
{ citire();
backrec(1,1,1);
g<<pmin<<" "<<nr<<endl;
backmin(1,1,1);
g<<"Nrsol="<<nrsol;
f.close();
g.close();
return 0;}
Bactracking cu fisiere
1.Se citesc doua numere naturale n si m (n,m<=10) si apoi o multime A cu n elemente
naturale
ordonate crescator. Afisati in ordine lexicografica toate submultimile cu m elemente ele
multimiiA in care nu exista doua elemente pare alaturate. Daca problema nu are solutie, se va
afisa mesajul “NU EXISTA”.
Exemple: n=5, m=3 si A={1,4,6,7,9} => {1, 4, 7} {1,4,9}, {1,6,7}, {1,6,9}...
n=4, m=3 si A={1,4,6,8} =>”NU EXISTA”
p1.in
53
14679
p1.out
147
149
167
169
179
479
679
nrsol=7
#include <fstream>
using namespace std;
ifstream f("p1.in");
ofstream g("p1.out");
int A[11],X[11],n,m,gasit=0,nrsol=0;
void afis()
{
for(int i=1;i<=m;i++)
g<<A[X[i]]<<" ";
1
g<<endl;
gasit=1;
nrsol++;}
void backrec(int k)
{ for(int i=X[k-1]+1;i<=n;i++)
{ X[k]=i;
if(k==1 || A[X[k]]%2==1 || A[X[k-1]]%2==1)//cel putin 1 impar
if(k==m) afis();
else backrec(k+1); }}
int main()
{ f>>n>>m;
for(int i=1;i<=n;i++)
f>>A[i];
backrec(1);
if(!gasit) g<<"NU EXISTA";
g<<"nrsol="<<nrsol;
f.close();
g.close();
return 0;}
2. Se citesc doua numere naturale n si s (n<=10, s<=20). Afisati in ordine crescatoare toate
numerele cu n cifre distincte care au suma cifrelor egala cu s. Daca problema nu are solutie,
se va afisa mesajul “NU EXISTA”.
Exemple: n=4, s=9 => 1026, 1035, 1053, 1062, 1206, 1260, 1305,…
n=4, s=5 =>NU EXISTA
#include <fstream>
using namespace std;
ifstream f("p3.in");
ofstream g("p3.out");
int X[11],n,s,P[11],gasit=0,nrsol=0;
void afis()
{int i;
for(i=1;i<=n;i++)
g<<X[i];
g<<endl;
gasit=1;
nrsol++;}
void backrec(int k,int sp)
{ for(int i=0;i<=9;i++)
if(!P[i])
{X[k]=i;
P[i]=1;
sp=sp+X[k];
if(X[1]!=0 && sp<=s)
if(k==n) { if(sp==s) afis(); }
else backrec(k+1,sp);
sp=sp-X[k];
P[i]=0; }}
int main()
{ f>>n>>s;
backrec(1,0);
if(!gasit) g<<"NU EXISTA";
g<<"nrsol="<<nrsol;
f.close();
g.close();
return 0;}
Programe Backtracking
1. Să se genereze toate funcţiile injective f:{1,2,…,n}--> {1,2,…,m}.
#include <iostream>
using namespace std;
int x[20],n,m,nrsol=0;;
void afisare()
{for (int i=1; i<=n; i++)
{cout <<"f("<<i<<")="<<x[i];
cout <<"\n";}
cout <<"\n";nrsol++;}
int valid(int k)
{for (int i=1;i<k;i++)
if (x[k]==x[i]) return 0;
return 1;}
void backrec(int k)
{int i;
for (i=1;i<=m;i++)
{ x[k]=i;
if (valid(k))
if (k==n) afisare();
else
backrec(k+1);}
}
int main()
{cout <<"n="; cin >>n; cout <<"m="; cin >>m;
if (m<n) cout <<"Nu exista functii injective.";
else backrec(1);
cout<<"Nr solutiilor="<<nrsol;
return 0;}
2. Să se genereze toate funcţiile surjective f:{1,2,…,n} -> {1,2,…,m}.
#include <iostream>
using namespace std;
int x[20],m,n,nrsol=0;
void afisare()
{
for(int i=1;i<=n;i++)
{
cout <<"f("<<(i)<<")="<<x[i];
cout <<"\n";}
cout <<"\n";
nrsol++;}
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 backrec(int k)
{for (int i=1;i<=m;i++)
{
x[k]=i;
if(k==n)
{if(valid(k))
afisare();
}
else backrec(k+1);
}}
int main()
{cout <<"n=";
cin >>n;
cout <<"m="; cin >>m;
if (m>n) cout <<"Nu exista functii surjective.";
else backrec(1);
cout<<"nrsol="<<nrsol;
return 0;}

3Î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,nrsol=0;
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<<" ";
cout<<"\n";nrsol++;
}
void backrec(int k)
{
int i;
for(i=st[k-1]+1;i<=n;i++)
t[k]=i;
if(i<=f) nr_f++;
if (k==m)
{if (nr_f==p)
afiseaza();
}
else backrec(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;
backrec(1);
cout<<"nrsol="<<nrsol;
return 0;}

4. 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],nrsol=0;
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";}
nrsol++;}
void backrec(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 backrec(k+1);
}}
int main()
{cout<<"Nr de margele din colier=";cin>>n;
backrec(1);
cout<<"nrsol="<<nrsol;
return 0;}
5 Se dă un număr natural s cu cel mult 9 cifre. Afișaţi, în ordine lexicografică, toate
modalităţile de a-l scrie pe s ca produs de divizori proprii distincți ai lui s.
Exemplu:
30 poate fi scris in următoarele moduri:
235
2 15
3 10
56
#include <iostream>
#include <algorithm>
using namespace std;

int D[401],X[401],n;
unsigned long long s;
void afisare(int k)
{
for(int i=1;i<=k;i++)
cout<<D[X[i]]<<" ";
cout<<"\n";
}
void back(int k, unsigned long long pp)
{
for(int i=X[k-1]+1;i<=n && pp*D[i]<=s;i++)
{
X[k]=i;
pp=pp*D[X[k]];
if(pp<=s)
if(pp==s) afisare(k);
else back(k+1,pp);
pp=pp/D[X[k]];
}
}

int main()
{
cin>>s;
for(unsigned long long i=2;i*i<=s;i++)
if(s%i==0)
{
D[++n]=i;
if(i*i!=s) D[++n]=s/i;
}
if(n==0) cout<<"NU EXISTA";
else
{
sort(D+1,D+n+1);
back(1,1);
}
return 0;
}

6 Se citeste un numar natural n si apoi o multime cu n elemente numere naturale.


Folosind interschimbari de elemente generati si afisati permutarile multimii citite.
#include <iostream>
using namespace std;
int x[20],n;
void afis()
{for (int i = 1; i <= n; i++) cout<<x[i]<<" ";
cout<<endl;
}
void inter(int &x, int &y)
{int aux=x; x=y; y=aux;
}
void perm(int k, int n)
{ for (int i = k; i <= n; i++)
{ inter(x[k], x[i]);
if(k==n) afis();
else perm(k+1, n);
inter(x[k], x[i]);
}}
int main()
{cin>>n;
for(int i=1;i<=n;i++) cin>>x[i];
perm(1,n);
return 0;
}
7 Se citeste un numar natural n. Afisati permutarile multimii 1,2,3...n in care pana la jumatate
elementele sunt in ordine descrescatoare, iar de la jumatate pana la final in ordine crescatoare.
Exemplu:
n=5
permutarile care respecta conditia sunt:
32145
42135
43125
52134
53124
54123
#include <fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");
int n, sol[20], p[20];
void afis()
{ for(int i=1;i<=n;i++)
fout<<sol[i]<<" ";
fout<<endl;}
int valid(int k)
{
if(k>1)
if(k<=(n+1)/2) { if(sol[k]>sol[k-1]) return 0; }
else if(sol[k]<sol[k-1]) return 0;
return 1;
}

void back(int k)
{
for(int i=1;i<=n;i++)
if(p[i]==0)
{
sol[k]=i;
p[i]=1;
if(valid(k)) if(k==n) afis();
else back(k+1);
p[i]=0;
}
}
int main()
{fin>>n;
back(1);
fin.close();
fout.close();
}
8Se citeste o matrice a cu n linii si m coloane care contine numere naturale. Afisati toate
modurile in care se poate parcurge matricea mergand in vecinii de sus, jos, stanga si dreapta
astfel incat prin fiecare element sa se treaca de atatea ori cat este valoarea lui.
Solutiile se vor afisa ca succesiune de pozitii si ca succesiune de directii.
Exemplu:
date.in
44
0100
1201
0112
0011
date.out
1,2 2,2 2,1 2,2 3,2 3,3 4,3 4,4 3,4 2,4 3,4
SVESESENNS
1,2 2,2 2,1 2,2 3,2 3,3 3,4 2,4 3,4 4,4 4,3
SVESEENSSV
2,1 2,2 1,2 2,2 3,2 3,3 4,3 4,4 3,4 2,4 3,4
ENSSESENNS
2,1 2,2 1,2 2,2 3,2 3,3 3,4 2,4 3,4 4,4 4,3
ENSSEENSSV
3,4 2,4 3,4 4,4 4,3 3,3 3,2 2,2 1,2 2,2 2,1
NSSVNVNNSV
3,4 2,4 3,4 4,4 4,3 3,3 3,2 2,2 2,1 2,2 1,2
NSSVNVNVEN
4,3 4,4 3,4 2,4 3,4 3,3 3,2 2,2 1,2 2,2 2,1
ENNSVVNNSV
4,3 4,4 3,4 2,4 3,4 3,3 3,2 2,2 2,1 2,2 1,2
ENNSVVNVEN
#include<fstream>
using namespace std;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
struct poz {int i,j;};
int a[20][20],p,n,m;
poz b[10000];
char dir[]="NSVE", x[10000];
ifstream f("r.in");
ofstream fout("r.out");
void afis(int k)
{ for(int i=1;i<=k;i++)
fout<<b[i].i<<","<<b[i].j<<" ";
fout<<endl;
for(int i=1;i<k;i++) fout<<x[i];
fout<<endl;
}
void back(int i, int j, int pas)
{ int k,inou,jnou;
a[i][j]--;
b[pas].i=i; b[pas].j=j;
if (pas==p) afis(p);
else for(k=0;k<4;k++)
{ inou=i+dx[k];
jnou=j+dy[k];
if (a[inou][jnou]>0)
{
x[pas]=dir[k];
back(inou,jnou,pas+1);
}}
a[i][j]++;}
int main()
{ int i,j;
f>>n>>m;
p=0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{f>>a[i][j];
p=p+a[i][j];}
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(a[i][j]>0) back(i,j,1);
return 0;
}
9 Un patrat de latura n este numit magic daca este format din numerele de la 1 la n*n si suma
pe fiecare linie, pe fiecare coloana, precum si pe cele 2 diagonale este constanta.
Exemplu:
276
951
438
#include<fstream>
#include<cstring>
using namespace std;
ifstream f("date.in");
ofstream g("date.out");
int n,p[100],a[10][10],s,gata;
void afis()
{ int i,j;
for(i=1;i<=n;i++)
{for(j=1;j<=n;j++)
g<<a[i][j]<<" ";
g<<endl;
}
g<<endl;
gata=1;
}
int sumap(int i,int j)
{int s=0,k;
for(k=1;k<=j;k++) s=s+a[i][k];
return s;
}
int sumal(int i)
{int s=0,j;
for(j=1;j<=n;j++) s=s+a[i][j];
return s;
}
int sumac(int j)
{int s=0,i;
for(i=1;i<=n;i++) s=s+a[i][j];
return s;}
int sumad2()
{int s=0,i;
for(i=1;i<=n;i++) s=s+a[i][n+1-i];
return s;}
int sumad1()
{int s=0,i;
for(i=1;i<=n;i++) s=s+a[i][i];
return s;
}
int bun(int i, int j)
{if(sumap(i,j)>s) return 0;
if(j==n) if(sumal(i)!=s) return 0;
if(i==n) if(sumac(j)!=s) return 0;
if(i==n && j==1) if(sumad2()!=s) return 0;
if(i==n && j==n) if(sumad1()!=s) return 0;
return 1;
}
void back(int i, int j)
{if(!gata)
for(int v=1;v<=n*n;v++)
if(!p[v])
{
a[i][j]=v;
p[v]=1;
if(bun(i,j)) if(i==n&&j==n) afis();
else if(j<n) back(i,j+1);
else back(i+1,1);
p[v]=0;
}}
int main()
{f>>n;
s=n*(n*n+1)/2;
gata=0;
back(1,1);
return 0;}
BIBLIOGRAFIE:
WIKIPEDIA
PBINFO
UPT.RO

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