Documente Academic
Documente Profesional
Documente Cultură
23
0 1 2 3 4 5 6 ..12 Din (1) si (2) => intervalul de cautare al divizorilor proprii ai lui n este [2,n/2]. Algoritmul consta in: -parcurgerea intervalului [2,n/2] cu ajutorul unui contor i si -verificarea fiecarei valori i daca este divizor sau nu al lui n II. Pasii algoritmului pas1. i = 2 pas2. daca i<=n/2 atunci pas3 altfel pas5 pas3. daca n%i = = 0 atunci scrie i pas4 altfel pas4 pas4. i=i+1 pas2 pas5.stop Ex: n=12
? da ? da
p1. i=2 => i<=n/2 => n%i= =0 => scrie i (2) 2 6 12 2 i=i+1 (i=3)
? da ? da
p2. i=3 => i<=n/2 => n%i= =0 => scrie i (3) 3 6 12 3 i=i+1 (i=4)
? da ? da
p3. i=4 => i<=n/2 => n%i= =0 => scrie i (4) 4 6 12 4 i=i+1 (i=5)
? da ? nu
p5. i=6 => i<=n/2 => n%i= =0 => scrie i (6) 6 6 12 6 i=i+1 (i=7)
nu
III. Secventa de program for(i=2;i<=n/2;i++) if (n%i = = 0) cout<<i<< ; //se parcurge cu i intervalul [2,n/2] //se verifica daca i este divizor al lui n
24
3. Numar prim
Enunt. Se da un numar n .Sa se afiseze un mesaj corespunzator daca numarul este prim sau nu. I. Partea teoretica Definitie: un numar este prim daca si numai daca are ca divizori pe 1 si el insusi. din def. => ca un numar este prim daca nu are nici un divizor propriu => nu exista nici un divizor oricare ar fi i [2,n/2]. Stim ca orice numar este un produs de 2 factori n=n1*n2 unde n1,n2 [2,n/2]=>deoarece este suficient sa gasim un divizor, adica n1 ca sa demonstram ca n nu e prim=> ca nu e necesar sa parcurgem tot intervalul [2,n/2]=>intervalul de cautare a unui divizor va fi intervalul corespunzator divizorului n1 adica [2, n ].
De ce [2, n ] ? Ex: fie n=6 => Cazuri 6= 2*3 , n1=2 n2=3 6=3*2 , n1=3 n2=2
2
n1
n2
n/2
n=6
Rezolvarea problemei: Parcurgem cu un contor i intervalul [2, n ] in speranta ca nu vom gasi nici un divizor=>Intrebarea ar fi :ce se intampla daca totusi gasesc un divizor? =>avem nevoie de o variabila logica ok cu care sa punem in evidenta daca am gasit sau nu un divizor=> initial ok=1 (adica presupunem ca n este prim) si daca vom gasi cel putin un divizor atunci ok=0 (adica presupunerea facuta initial ca n este prim este falsa). (1) Din (1) => ca daca gasim cel putin un divizor deja stim ca n nu mai este prim =>numai are rost sa parcurgem restul intervalului
=> conditia de cautare a primului divizor este: i <= n && ok= = 1. II. Pasii algoritmului pas1. ok=1, i=2 pas2 pas2. daca i <= n && ok=1 =>pas3 altfel pas6 pas3. daca n mod i=0 =>pas4 altfel pas5 pas4. ok=0 =>pas5 pas5. i=i+1 =>pas2 pas6.daca ok=0 scrie nu e nr. prim altfel scrie nr. e prim Ex1: n=12
2
12 12 2
da
da
p1. ok=1,i=2 => i <= n && ok=1=> n%i=0 => ok=0,i=i+1(3) p2. ok=0, i=3 => i <= n && ok=1=> ok=0=> scrie nu este nr.prim da
3 12
Ex2: n=13
13
13 2 da nu
p3. ok=1, i=4 => i <= n && ok=1=> ok=0 => scrie nr. prim III. Secventa de program for (i=2,ok=1; i<= n && ok; i+ +) //se parcurge cu contorul i intervalul [2, n ] cat timp nu s-a gasit nici un divizor if (n%i = = 0) // se verifica daca i este divizor ok=0; //daca este i divizor atunci presupunerea facuta (ok=1) ca n este prim devine falsa adica ok=0 if(ok) // daca nu s-a gasit nici un divizor(ok=1),deci presupunerea ca n este prim a ramas adevarata cout<<nr.prim; else cout<<nr. nu e prim;
25
Enunt(Algoritmul lui Euclid): Se executa impartiri succesive pana cand restul devine 0. C.m.m.d.c. este ultimul impartitor obtinut.Initial deimpartitul si impartiorul sunt numerele citite, apoi deimpartitul devine impartitorul din impartirea anterioara, iar impartitorul devine restul din impartirea anterioara.
II. Pasii algoritmului si Secventa de program Se disting 4 cazuri: Caz 1. a>b Ex: a=30 b=14 I. 30: 14 = 2 28 --=2 p1. d=a(30) i=b(14) r=d%i=2 d=i(14) i=r(2) II. 14: 2 = 7 14 ---=0 p2. d=14 i=2 r=d%i=0 => c.m.m.d.c.=2
Secventa de program corespunzatoare: d=a; i=b; while(d%i!=0) { r=d%i; d=i; i=r; } cout<<cmmdc=<<i; Caz 2. a<b Ex: a=14 b=30 I. 14: 30 = 0 0 --=14 II. 30: 14 = 2 28 ---=2 III. 14: 2 = 7 => c.m.m.d.c.=2 14 ---=0 for(d=a, i=b; d%i !=0; r=d%i, d=i, i=r); cout<<cmmdc=<<i;
p1. d=a(14) p2. r=d%i=2 p3. d=14 i=b(30) d=i(14) i=2 r=d%i=14 i=r(2) r=d%i=0 d=i(30) i=r(14) Obs: Se observa ca acest caz este similar cu caz1(a>b) cu deosebirea ca apare un pas suplimentar care are ca efect inversarea valorilor din a si b. Deci caz 2 se reduce la caz 1 dupa ce se efectueaza o impartire suplimentara.=> secventa de program de la cazul 1 este valabila si pentru cea de la cazul 2. Caz 3. a=0 b0 Ex: a=0 b=14 Se stie din matematica, ca c.m.m.d.c.(0,b)=b (cmmdc dintre 0 si orice numar diferit de 0 este acel numar). Ne propunem sa verificam daca algoritmul lui Euclid rezolva aceasta situatie.
26
I. 0: 14 = 0 0 --=0
=> c.m.m.d.c.=14
p1. d=a(0) i=b(14) r=d%i=0 Se observa ca acest caz particular este rezolvat cu succes de algoritm=> secventa de program de la cazul 1 este aplicabila si in acest caz. Caz 4. a 0 b=0 Ex: a=14 b=0 Se stie din matematica, ca: cmmdc(a,0) este a (1) Oare algoritmul lui Euclid rezolva acest caz particular? I. 14: 0 = imposibil => aparent algoritmul este impracticabil DAR.. Conform teoriei matematice cmmdc(14,0) ar trebui sa fie 14 adica deimpartitul. Presupunem ca a=28 b=14 I. 28:14= 2 II. 14:0=imposibil 28 cmmdc ---=0 p1. d=a(28) i=b(14) r=d%i=0 d=i(14) i=0 Teoretic Euclid spune ca algoritmul se incheie atunci cand restul devine 0 si cmmdc este impartitorul=> daca vom forta algoritmul cu inca un pas se observa ca se ajunge tocmai la cazul 4 in care deimpartitul este tocmai cmmdc=>deci regula matematica cmmdc(a,0)=a este indeplinita => algoritmul lui Euclid rezolva si cazul4. Deci algoritmul lui Euclid rezolva toate cazurile cu conditia sa aducem le aducem pe toate pana la cazul 4=>conditia de oprire a algoritmului va fi ca impartitorul sa fie zero(restul din impartirea precedenta pentru cazurile 1,2,3), iar deimpartitul(impartitorul din impartirea precedenta) va fi cmmdc. Secventa de program valabila oricare ar fi a si b este: d=a; i=b; while(i!=0) { r=d%i; d=i; i=r; } cout<<cmmdc=<<d; for(d=a, i=b; i !=0; r=d%i, d=i, i=r); cout<<cmmdc=<<d;
cmmdc(a,b)=
27
Rezolvarea problemei presupune scaderi repetate fie din a (daca a>b) fie din b(daca b>a) pana cand a=b moment in care algoritmul se termina => cmmdc va fi a sau b(a=b).Cazurile particulare a=0,b0 si a0,b=0 se trateaza separat de algoritm. II. Pasii algoritmului pas1. daca a=b pas5 altfel pas 2 pas2. daca a>b pas 3 altfel pas 4 pas3. a=a-b pas1 pas4. b=b-a pas1 pas5. scrie a (b) Ex: a=12 b=18 12 18 nu 12 18 nu p1. a=12, b=18 => a=b=> a>b => b=b-a=6
12 6
nu
12
6 da
p3.a=6,b=6=>a=b=> scrie cmmdc=a=6 =>stop. III. Secventa de program if (a= =0 || b= =0) //daca a=0 sau b=0 cmmdc este suma lor(cazurile particulare) cout<<cmmdc=<<a+b; else { while(a!=b) // cat timp ab se executa algoritmul if (a>b) a- =b; else b- =a; cout<<cmmdc=<<a; }
28
II. Pasii algoritmului pas1. i=2 pas2. daca n!=1 atunci pas3 altfel pas6 pas3. daca n%i= =0 atunci scrie i =>pas4 altfel pas5 pas4. daca n%i= =0 atunci n=n/i =>pas4 altfel pas5 pas5. i=i+1 =>pas2 pas6.stop Ex: n=180 180 da 180 2 da 180 2 da 180 2 da 90 2 da 90 2 45 2 nu p1. i=2,n=180 => n!=1 => n%i= =0 => scrie 2 =>n%i= =0 => n=n/i=90=> n%i= =0 => n=n/i=45=> n%i= =0 => i=i+1=3
da 45 3 da 45 3 da 45 3 da 15 3 da 15 3 5 3 nu
p2. i=3,n=45 => n!=1 => n%i= =0 => scrie 3 =>n%i= =0 => n=n/i=15=> n%i= =0 => n=n/i=5=> n%i= =0 => i=i+1=4
da 5 4 nu
p4. i=5,n=5 => n!=1 => n%i= =0 => scrie 5 => n%i= =0 => n=n/i=1=> n%i= =0 =>i=i+1=6
nu
III. Secventa de program for(i=2; n!=1; i++) // se parcurg divizorii lui n ,incepand de la primul numar prim(2),cat timp acesta se mai poate descompune if (n%i= =0) //daca i este divizor atunci se afiseaza si se imparte succesiv numarul la el eliminandu-se astfel toti multipli lui { cout<<i<< ; while (n%i= =0) n/=i; }
Enunt(Algoritmul lui Euclid)- Conversia unui numar n, in baza q, presupune impartirea repetata a lui n la q pana cand catul impartirii este 0. Noul numar nq, obtinut din conversia numarului n in baza q, este alcatuit din resturile obtinute in urma impartirilor repetate luate in ordinea inversa realizarii lor(nq=rk-1rk-2..r1r0) unde k-numarul de cifre din nq.
Ex: n(10) nq(q) n=13 q=2 cf.Algoritmului lui Euclid =>
=> nq= r3r2r1r0 =1101(2) Rezolvarea problemei consta in: - impartirea repetata a lui n la q pana cand catul(ce va deveni noul n) este 0. - construirea progresiva a lui nq(de la pas la pas). Obs.1.La fiecare pas dupa impartire catul obtinut din impartirea curenta va deveni in pasul urmator noua valoare a lui n. 2.Se necesita a se determina o formula de calcul a lui nq. 3.Initial nq=0.
29
0 1
1
2
pas3.n=3,q=2,nq= r1r0=1 => n!=0 => nq= r2r1r0=r2*10 + r1r0=r2*10 +nq=101 , n=n/q=1
1 da 1 1 0 1 1
3
1 0 1
1
3
101
1 2
pas4.n=1,q=2,nq= r2r1r0=101 => n!=0 => nq= r3r2r1r0= r3 *10 + r2r1r0= r3 *10 +nq=1101 , n=n/q=0
nu
pas5.n=0,q=2,nq= r3r2r1r0=1101 => n!=0 =>scrie 1101 Nota: 1.Se observa ca formula de calcul a lui nq este:
nq=r*10i-1+nq
unde i [1,k] k- numarul de cifre a lui nq(numarul de impartiri) . r- al i-lea rest obtinut din impartirea lui n la q.
2.Pentru a putea calcula in mod eficient 10k vom folosi o variabila p in care se vor calcula in mod iterativ (de la un pas la altul) puterile lui 10. Initial p=1(100) iar formula de calcul a lui p va fi: p=p*10 =>formula de calcul a lui nq este:
nq=r*p+nq
Algoritmul pe pasi este: p1.nq=0,p=1 p2.daca n!=0 atunci p3 altfel p4 p3.nq=n%q *p + nq n=n/q p=p*10 => p2 p4.scrie nq III. Secventa de program nq=0; //initial nq=0 p=1; //initial p=1=100 while(n!=0) { nq=n%q+nq; n=n/q; p=p*10; //creste puterea pentru pasul urmator // p=10k+1=10k*10 } cout<< nq; for(nq=0,p=1 ; n!=0 ; nq=n%q*p+nq, n/=q, p*=10) ; cout<< nq;
30
Obs. 1. Calculul numarului in baza 10 se poate face iterativ(pas cu pas) prin calculul unei sume de termeni. 2. Fiecare termen al sumei este alcatuit dintr-o cifra a numarului nq si o putere a lui q. 3. Deoarece cifrele lui nq se pot obtine prin algoritmul de eliminare a cifrelor => primul termen din suma va fi : r0*q0 => formula generala de calcul a lui n va fi :
n=ri-1*qi-1 +n
unde i [1,k] , k-numarul de cifre din nq 4. Calculul puterii lui q ( qk-1=q*qk-2 ) se va face tot iterativ folosind o variabila p astfel: p=q0=1(initial) p=p*q (in caz general) => formula generala de calcul a lui n va fi :
n=ri-1*p +n
unde i [1,k] , k-numarul de cifre din nq
Rezolvarea problemei consta in:-extragerea fiecarei cifre din nq cat timp nq!=0 si -calculul sumei, prin adaugarea noului termen Nota: La fiecare pas se aduna un termen de forma : ri-1*p , unde p=q II. Pasii algoritmului p1. p=1,n=0 p2.daca nq!=0 atunci p3 altfel p4 p3.n=nq%10*p+n p=p*q nq=nq/10 =>p2 p4. scrie n Ex: nq=10101 da 1 1 0 pas1.nq=10101, n=0, p=20=1 => nq!=0 => n=nq%10*p+n=1,
da 0 2 1 1 2
i-1
p=p*q=1*2=21,
2 2
p=p*q=23*2=24,
16 2
pas6.nq=0, n=21,p=2 => nq!=0 => scrie 21 III. Secventa de program n = 0; //initial n=0 p = 1; //initial p=20=1 while(nq!=0) { n = nq%10 * p + n; //se calculeaza n ca o suma p * = q; //creste puterea p nq / =10; //se elimina ultima cifra din nq } cout<< n; for(n=0,p=1; nq!=0 ; n=nq%10*p+n, p*=q, nq/=10) ; cout<< n;
31