Sunteți pe pagina 1din 5

Algoritmul lui euclid

Proiect realizat de Catalin Nicusor Claudiu

În acest articol voi prezenta conceptele de CMMDC (cel mai


mare divizor comun) și CMMMC (cel mai mic multiplu
comun), precum și Algoritmul lui Euclid, atât prin scăderi
repetate, cât și prin împărțiri repetate. La final, vom discuta
despre câteva aplicații la CMMDC și CMMMC.

Cel mai mare divizor comun (CMMDC)


Cel mai mare divizor comun a două numere
naturale a și b este efectiv cel mai mare număr natural care îl
divide atât pe a, cât și pe b. Acesta se notează cmmdc(a,b),
gcd(a,b) (de la greatest common divisor) sau pur și
simplu (a,b).

De
exemplu, (20,24)=4(20,24)=4, (6,3)=3(6,3)=3, (14,5)=1(14,5)
=1 și (0,18)=18(0,18)=18. Există un singur caz în care
valoarea (a,b) nu e definită, și anume atunci când a=b=0. Asta
pentru că 0 este divizibil cu toate numerele naturale nenule.
Nu putem spune că (a,b)=∞.
Să luăm un exemplu mai mare: a=229320 și b=996072. Dacă
descompunem în factori primi numerele a, b și (a,b), obținem:
De aici observăm că putem defini CMMDC-ul a două numere
drept produsul dintre factorii lor comuni luați la cea mai
mică putere. Este cât se poate de logic: Dacă am scădea
puterea unui factor din descompunerea lui (a,b) am obține un
CMMDC mai mic, iar dacă am mări-o, cel puțin unul dintre
cele două numere nu va mai fi divizibil cu noul CMMDC.
Cel mai mic multiplu comun (CMMMC)
Cel mai mic multiplu comun a două numere naturale nenule
este cel mai mic număr natural nenul care este divizibil atât cu
a, cât și cu b. Acesta se notează cmmmc(a,b), lcm(a,b) (de
la least common multiple) sau [a,b]. De
exemplu, [20,24]=120[20,24]=120, [3,5]=15[3,5]=15, [12,4]=
12[12,4]=12 și [1,7]=1[1,7]=1.
Din nou, vom lua un exemplu mai complex ca să analizăm
descompunerile în factori primi ale
numerelor a, b și [a,b]. Fie a=840 și b=126:
De aici, putem observa că CMMMC-ul a două numere este
egal cu produsul dintre factorii lor comuni și necomuni luați
la cea mai mare putere.
Algoritmul lui Euclid prin scăderi repetate
Algoritmul lui Euclid este o metodă foarte simplă și eficientă
de a calcula CMMDC-ul a două numere. Există două variante
ale Algoritmului lui Euclid: una prin scăderi repetate și
cealaltă prin împărțiri repetate. Prima nu este nici pe departe la
fel de eficientă precum a doua, dar voi începe cu ea pentru că
ne ajută să înțelegem mai ușor varianta prin împărțiri.
Algoritmul lui Euclid prin scăderi repetate presupune să
scădem la fiecare pas numărul mai mic din numărul mai mare,
până când unul dintre ele devine 0. La final, valoarea
numărului care a rămas nenul va fi egală cu(a,b).
while (a && b)
if (a > b)
a -= b;
else
b -= a;
cout << a + b << '\n';

Se observă că algoritmul acesta modifică valorile inițiale ale


variabilelor a și b. Deci, dacă avem nevoie de ele mai târziu,
putem să le facem copii la început, și să folosim copiile în
cadrul algoritmului. Sau, mai simplu, definim o funcție gcd,
care primește ca parametri numerele a și b și returnează (a,b):

// ...

int gcd(int a, int b) {


while (a && b)
if (a > b)
a -= b;
else
b -= a;
return a + b;
}

// ...

int main() {
int a, b; cin >> a >> b;
cout << gcd(a, b) << '\n';
return 0;
}

Algoritmul lui Euclid prin împărțiri repetate


Să ne uităm cum evoluează perechea de
numere (a,b)=(18,5) în cazul algoritmului precedent:
(18,5)→(13,5)→(8,5)→(3,5)(18,5)→(13,5)→(8,5)→(3,5)
L-am scăzut pe b din a până când a a devenit mai mic
decât b. Practic, am simulat procesul de împărțire a
lui a la b prin scăderi repetate. Astfel, la final a a
devenit amodb, adică restul împărțirii lui a la b. Așadar, putem
optimiza algoritmul inițial împărțind la fiecare pas numărul
mai mare la cel mai mic, și reținând în acesta restul împărțirii.
În cazul de mai sus economisim doi pași, însă în
cazul (a,b)=(109,1) economisim un miliard de pași.
while (a && b)
if (a > b)
a %= b;
else
b %= a;
cout << a + b << '\n';

Iată și o implementare ceva mai elegantă:


while (b) {
int r = a % b;
a = b;
b = r;
}
cout << a << '\n';

La fiecare pas, îl copiem pe b în a și pe r (restul împărțirii)


în b, menținând astfel invariantul a>b. Numai la primul pas
este posibil ca acesta să nu fie îndeplinit. Dacă
inițial a=b, algoritmul se termină într-un pas, iar
dacă a<b, numerele se inversează după primul pas, a devenind
mai mare decât b.

Problema in C++

O instalație de Crăciun consistă din n≥1 becuri de diferite


culori. Știind că inițial toate becurile sunt aprinse și că
fiecare bec i (cu 1≤i≤n) se aprinde din ti în ti secunde, să se
determine după cât timp toate becurile vor fi aprinse
simultan din nou.
Răspunsul trebuie să fie divizibil cu fiecare dintre timpii
dați. Cum ne interesează prima dată când toate becurile
vor fi aprinse din nou, vom calcula lcm(t1,t2,…,tn):

int ans = 1;
for (int i = 1; i <= n; i++)
ans = lcm(ans, t[i]);
cout << ans << '\n';

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