Sunteți pe pagina 1din 5

MI neintensiv cls a X-a recapitulare

Divizibilitate – noțiuni aprofundate

1. Calculul numărului de divizori ai unui număr natural

Metoda naivă – presupune parcurgerea intervalului [1,n] și testarea fiecărui număr din interval dacă este
divizor a lui n. Această metodă are o complexitate O(n).

Implementare C++

int k=0;
for(int d=1;d<=n;d++){
if(n%d==0) k++;
}
cout<<”nr. de divizori=”<<k;

Obs: putem reduce intervalul de căutare la [2,n/2] ținând cont de faptul că niciun divizor a lui n nu se
găsește în intervalul [n/2+1,n-1], iar inițial stabilim k=2 (divizorii improprii) pentru n>=2.

Metoda optimizată

Dacă d este divizorul lui n se poate observa că și n/d este divizor a lui n deoarece d * (n/d) = n.
În acest fel putem stabili direct doi divizori.

Exemplu 1: Exemplu 2:

n=42 n=36
d n/d d n/d
2 21 2 18
3 14 3 12
6 7 4 9
7 6 6 6
14 3 9 4
21 2 12 3
18 2

În exemplul 1 observăm că în prima jumătate avem aceeași dizivori ca și în a doua jumătate, dar în altă
ordine. Totodată divizorii din prima jumătate sunt toți divizorii proprii ai lui n.

În prima jumătate se respectă relația d <= n/d . Dacă înmulțim ambii membri ai inegalității cu d vom avem
d*d <= n . Extragem radical din ambii membri ai inegalității și obținem d <= √𝑛. Observăm că este suficient
să parcurgem intervalul [2, √𝑛], ceea ce duce la o complexitate a algoritmului O(√𝒏).

1 prof. Rotar Dorin-Mircea


MI neintensiv cls a X-a recapitulare

În exemplul 2 se observă că în cazul numerelor pătrate perfecte avem un număr impar de dizivori, cazul d*d
= n trebuie tratat separat.

Implementarea în C++:

int k=2,d;
if(n==1){
cout<<n;
return 0;
}
for(d=2; d*d<n; d++){
if(n%d == 0){
k+=2;
}
}
if(d*d == n){
k++;
}
cout<<k;

OBS: Zero se divide cu orice număr diferit de zero. Zero are un număr infinit de divizori.

2 prof. Rotar Dorin-Mircea


MI neintensiv cls a X-a recapitulare

2. Stabilirea primelor n numere prime – Ciurul lui Eratostene

Ciurul lui Eratostene este un algoritm clasic folosit pentru determinarea tuturor numerelor prime mai mici
sau egale cu un număr natural dat n.

Algoritm
1) Se scrie pe o foaie o listă cu toate numerele naturale de la 2 la n.
2) Se caută în listă primul număr care nu a fost tăiat (și pe care încă nu l-am folosit).
3) Se taie de pe foaie toți multiplii numărului ales mai înainte, cu excepția lui.
4) Dacă încă nu am ajuns la finalul listei căutând numere netăiate, se revine la pasul 2.

Exemplu: n=16
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
x X x x x x x x x

Implementare
Reținem un vector sieve (ciur în engleză), de tip bool, cu semnificația sieve[i] == true dacă numărul i nu este
prim, iar false dacă i este prim. Am ales codificarea pe dos pentru că în C++ vectorii globali sunt automat
inițializați cu 0, și n-are rost să mai facem o parcurgere pentru a-l schimba pe 0 în 1. Cum numerele 0 și 1 nu sunt
nici prime, nici compuse, le vom marca de la început cu true: sieve[0] = sieve[1] = true;.

Apoi, alegem primul număr cu valoarea false din vectorul sieve, și marcăm multiplii săi cu true. Repetăm acest
proces până când toate numerele neprime din sieve vor fi marcate cu true.

Implementare C++
sieve[0] = sieve[1] = true;
for (int i = 2; i <= n; i++) // Parcurgem vectorul sieve.
if (!sieve[i]) // Dacă numărul curent este prim,
for (int j = 2 * i; j <= n; j += i) // parcurgem multiplii săi
sieve[j] = true; // și îi marcăm drept numere compuse.

3 prof. Rotar Dorin-Mircea


MI neintensiv cls a X-a recapitulare

3. Calcularea numărului de divizori al unui interval de numere

În cazul avem de calculat numărul de divizori pentru mai multe numere dintr-un interval finit de numere
naturale se recomandă folosirea unui vector caracteristic în care se reține numărul de divizori ai fiecărui număr
din interval.

Mecanismul prin care se identifică numerele prime specific Ciurului lui Eratostene poate fi folosit și la
determinarea altor rezultate. De exemplu, vrem să aflăm pentru un n dat (nu prea mare) câți divizori are fiecare
număr natural din intervalul [1,n].

Pentru acesta, vom construi un vector v, în care v[x] reprezintă numărul de divizori ai lui x. Pentru a construi
acest vector, vom parcurge numerele de la 1 la n, și pentru fiecare număr x vom identifica multiplii săi. Pentru
fiecare y multiplu al lui x vom incrementa valoarea lui v[y].

Implementarea C++

const int NN=100000;


int v[NN+1];
for(int i=2; i<=NN/2; i++){
for(int j=2*i; j<=NN; j+=i) /// i este divizor al lui j
v[j]++;
}
for(int i=2; i<=NN; i++) v[i]+=2; //adaugam divizorii improprii

Probleme propuse:

1) Se dă un șir de n numere naturale nenule. Determinați pentru fiecare număr din șir care este cel mai
mare divizor impar al său.[ Divizori impari – pbinfo]
2) Se dă un şir format din n numere naturale nenule. Aflaţi cel mai mic număr natural, diferit de 1, care
divide un număr maxim de numere din şir. [divizor112 - pbinfo]
3) Gigel a descoperit un nou joc. Jocul are n nivele și la fiecare nivel îți dă câte un număr natural x.
Pentru a trece nivelul trebuie să calculezi câți divizori are numărul x. Scrieți un program care să
permită terminarea jocului prin trecerea celor n nivele în ordinea în care sunt date. [joc2020 - pbinfo]

4 prof. Rotar Dorin-Mircea


MI neintensiv cls a X-a recapitulare

Bibliografie:
1) Arta programarii calculatoarelor, volumul 1. Algoritmi fundamentali, Autor Donald E.
Knuth, Editura Teora, 2000
2) Programarea in limbajul C/C++ pentru liceu : Programarea in limbajul C/C++ pentru liceu,
Emanuela Cerchez, Marinel-Paul Serban, Editura Polirom, 2005
3) https://www.geeksforgeeks.org/sieve-of-eratosthenes/
4) www.pbinfo.ro

5 prof. Rotar Dorin-Mircea

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