EXERCIŢII DE ARITMETICĂ Exerciţiul 1 Să se determine dacă un număr introdus i ntrodus de la tastatură este număr prim sau nu. Soluţie Condiţia suficientă ca un număr n număr n să fie prim este ca acesta să nu se dividă cu nici un alt număr din intervalul 1..[ ]. n
program nr_prim; uses crt; var n:word; a:real; i,m:word; prim:boolean; begin clrscr; write('Introduceti numarul pentru test '); readln(n); prim:=true; a:=n; m:=trunc(sqrt(a)); i:=2; while(i<=m) and prim do if (n mod i) = 0 then prim:=false else i:=i+1; if prim then writeln('Numarul este prim') else writeln('Numarul nu este prim'); readln; end. Exerciţiul 2 Să se determine suma şi produsul a două polinoame. Soluţie: Fie polino polinoame amele le p1, p2 cu deg(pi)=gradi, i=1..2 i=1..2 şi grad=m grad=max( ax(gra gradd1, grad2). Suma celor două polinoame se calculează după formula: suma[i]= p1[i]+p2[i], i=1..grad i=1..grad (dacă unul din gradele celor două grad, coeficienţii “lipsă” sunt 0). Produsul celor două polinoame se polinoame este strict inferior lui grad, calculează după formula: i
produs [i] = ∑ p 1 [ j] ⋅ p 2 [i − j] , i=0..grad1+grad2. j=0
Polinoamel Polinoamelee sunt reprezentate reprezentate prin vectorii vectorii coeficienţilo coeficienţilorr cores-punz cores-punzători ători.. Gradele Gradele polinoamel polinoamelor, or, precum şi coeficienţii corespunzători vor fi introduşi de la tastatură.
program polinoame; uses crt; var p1,p2,suma,produs:array[0..40 p1,p2,suma,produs:array[0..40]] of integer; i,j,grad1,grad2,grad: i,j,grad1,grad2,grad: integer;
1
procedure sumapol; var k:integer; begin for k:=0 to grad do suma[k]:=p1[k]+p2[k] end; procedure produspol; var k,l,prod:integer; k,l,prod:integer; begin for k:=0 to grad1+grad2 do begin prod:=0; for l:=0 to k do prod:=prod+p1[l]*p2[k-l]; produs[k]:=prod end end; {programul principal} begin clrscr; write('Dati gradul maxim al polonmului1 '); readln(grad1); write('Dati coeficientii primului polinom '); for i:=0 to grad1 do readln(p1[i]); write('Dati gradul maxim al celui de-al doilea polinom'); readln(grad2); write('Dati coeficientii celui de-al doilea polinom '); for i:=0 to grad2 do read(p2[i]); if grad1>grad2 then grad:= grad1 else grad:=grad2; sumapol; produspol; writeln('Suma polinoamelor este: '); for i:=0 to grad-1 do if( suma[i+1]>=0)then write(suma[i],'*X^',i,'+') else write(suma[i],'*X^',i); writeln(suma[grad],'*X^',grad); writeln('Produsul polinoamelor este: '); for i:=0 to grad1+grad2-1 do if( produs[i+1]>=0)then write(produs[i],'*X^',i,'+') else write(produs[i],'*X^',i); writeln(produs[grad1+grad2],'*X^',grad1+grad2); end. Exerciţiul 3 Să se genereze toate permutările mulţimii {1, 2,..., n}, unde n este un număr natural citit de la tastatură, n ≤ 7. Soluţie: Problema Problema va fi rezolvată rezolvată utilizându-se utilizându-se metoda metoda backtracking . Forma standard a acestei metode se aplică problemelor în care trebuie găsit un vector x=(x1, x2, ..., xn) din spaţiul soluţiilor S=S1× S2× ...× Sn
2
procedure sumapol; var k:integer; begin for k:=0 to grad do suma[k]:=p1[k]+p2[k] end; procedure produspol; var k,l,prod:integer; k,l,prod:integer; begin for k:=0 to grad1+grad2 do begin prod:=0; for l:=0 to k do prod:=prod+p1[l]*p2[k-l]; produs[k]:=prod end end; {programul principal} begin clrscr; write('Dati gradul maxim al polonmului1 '); readln(grad1); write('Dati coeficientii primului polinom '); for i:=0 to grad1 do readln(p1[i]); write('Dati gradul maxim al celui de-al doilea polinom'); readln(grad2); write('Dati coeficientii celui de-al doilea polinom '); for i:=0 to grad2 do read(p2[i]); if grad1>grad2 then grad:= grad1 else grad:=grad2; sumapol; produspol; writeln('Suma polinoamelor este: '); for i:=0 to grad-1 do if( suma[i+1]>=0)then write(suma[i],'*X^',i,'+') else write(suma[i],'*X^',i); writeln(suma[grad],'*X^',grad); writeln('Produsul polinoamelor este: '); for i:=0 to grad1+grad2-1 do if( produs[i+1]>=0)then write(produs[i],'*X^',i,'+') else write(produs[i],'*X^',i); writeln(produs[grad1+grad2],'*X^',grad1+grad2); end. Exerciţiul 3 Să se genereze toate permutările mulţimii {1, 2,..., n}, unde n este un număr natural citit de la tastatură, n ≤ 7. Soluţie: Problema Problema va fi rezolvată rezolvată utilizându-se utilizându-se metoda metoda backtracking . Forma standard a acestei metode se aplică problemelor în care trebuie găsit un vector x=(x1, x2, ..., xn) din spaţiul soluţiilor S=S1× S2× ...× Sn
2
unde, pentru orice 1≤ i ≤ n, Si = si (număr finit de elemente) şi pe Si este definită o relaţie de ordine, iar x reprezintă reprezintă soluţia rezultat rezultat satisfăcând satisfăcând condiţiile condiţiile interne interne corespunză corespunzătoare toare problemei. problemei. Ca variante variante de ieşiri ieşiri sunt sunt posi posibi bile le cazu cazuri rile: le: o sing singur urăă solu soluţie ţie rezu rezulta ltat, t, toat toatee solu soluţii ţiile le rezu rezulta ltatt (în (în prob proble leme me de gene genera rare re asemănătoare celei propuse), o soluţie rezultat care optimizează (minim sau maxim) un criteriu f:S→R. Construcţia unei soluţii se face astfel: • se presupun determinate la momentul curent x1, x2, ..., xk ; • dacă secvenţa anterior calculată satisface condiţiile de continuare specifice problemei (dacă există şansa de a se obţine o soluţie rezultat) se alege xk+1 ∈ Sk+1 • altfel, dacă xk are succesor în Sk , xk ← succ(xk ) • altfel, dacă xk nu are succesor în Sk , se procedează în aceeaşi manieră cu “resatisfacerea” lui xk1. Procedura generală de calcul este următoarea:
procedure back(k:byte); begin if k=n+1 then final else begin x[k]:=init(k); while succ(k) do if continuare(k) then back(k+1); end; end; în care: • final este o procedură specifică momentului în care s-a determinat o soluţie rezultat x (se afişează rezultatul, se testează o funcţie criteriu criteri u pentru soluţia obţinută, aceasta selectându-se doar în anumite condiţii de optim samd); • init(k) este o funcţie de iniţializare a lui xk cu predecesorulu primului element din Sk ; • succ(k) este o funcţie booleană care testează existenţa succesorului lui xk în Sk şi dacă acest lucru este posibil se înlocuieşte xk cu succesorul lui din Sk ; • continuare(k) este o funcţie booleană care testează condiţiile de continuare (dacă secvenţa determinată până la momentul curent poate duce la o soluţie rezultat). În continuare este prezentată problema generării tuturor permutărilor mulţimii {1, 2,..., n} aplicânduse exact metoda generală şi ţinându-se cont de următoarele aspecte: • S1 = S2 = ... = Sn = {1, 2,..., n} (deci funcţia init nu depinde de nici un parametru, întorcând valoarea 0 indiferent de indicele elementului de iniţializat); • condiţia ca secvenţa {x1, x 2,..., xk } să fie una corectă pentru a se iniţia generarea lui xk+1 (ştiind că {x1, x2,..., xk-1} este corectă) este cea dată de definiţia unei permutări: xk ∉ {x1, x2,..., xk-1}. Programul Pascal este:
program permutare; uses crt; type tip_elem=0..7; var x:array[1..7] of tip_elem; n:byte; function init:byte; begin init:=0; end;
3
function succ(k:byte):boolean; begin succ:=x[k]x[k]) do inc(i); continuare:=i=k; end; procedure final; var i:byte; begin for i:=1 to n do write(x[i],' '); readln; end; procedure back(k:byte); begin if k=n+1 then final else begin x[k]:=init; while succ(k) do if continuare(k) then back(k+1); end; end; begin clrscr; write('Numarul de elemente al permutarii: '); readln(n); back(1); end. După cum se poate remarca, unele din opera]iile precedente (cum ar fi funcţia init , lucrul cu funcţia succ în condiţiile în care S1 = S2 = ... =Sn = {1, 2,..., n}) pot fi reformulate într-o manieră ce simplifică scrierea programului. De exemplu, o altă variantă corectă de rezolvare este:
program permutare_1; uses crt; type tip_elem=0..7; var x:array[1..7] of tip_elem; n:byte; procedure final;
4
var i:byte; begin for i:=1 to n do write(x[i],' '); readln; end; function continuare(k:byte):boolean; var i:byte; begin i:=1; while(ix[k]) do inc(i); continuare:=i=k; end; procedure back(k:byte); var i:byte; begin if k=n+1 then final else for i:=1 to n do begin x[k]:=i; if continuare(k) then back(k+1); end; end; begin clrscr; write('Numarul de elemente al permutarii: '); readln(n); back(1); end. Problema 5 Să se scrie programul Pascal pentru generarea tuturor submulţimilor mulţimii {1, 2,..., n}, unde n este un număr natural citit de la tastatură, n ≤ 10. Soluţie Se vor genera, prin metoda backtracking, toate submulţimile cu k elemente, 1 ≤ k ≤ n. Modul de reprezentare a unei submulţimi SubS a lui S (privite ca vectori) este:
0 ,S ∉ [ S i ] S u =b S [ i ] 1, S ∈ [ S i ] Condiţiile de continuare sunt cele ce caracterizează o submulţime a unei mulţimi, momentul terminării generării unei soluţii - o submulţime cu k elemente - sesizându-se când suma elementelor vectorului generat este k. În momentul determinării unei submulţimi, aceasta este trecută într-un vector, generându-se astfel P({1, 2,..., n}). Programul Pascal este:
5
program submultime; type elem=0..1; sub=array[1..10] of elem; var n,dim:byte; x:sub; tot:array[1..200] of sub; k,j:integer; nr:byte; function suma(t,k:byte):boolean; var s,i:byte; begin s:=0; for i:=1 to t do s:=s+x[i]; if s<=k then suma:=true else suma:=false; end; function sumaf:byte; var s,i:byte; begin s:=0; for i:=1 to n do s:=s+x[i]; sumaf:=s; end; procedure back(k,t:byte); var i:byte; begin if (t=n+1) then if(sumaf=k) then begin inc(nr); for i:=1 to n do tot[nr][i]:=x[i]; end else else for i:=2 downto 1 do begin x[t]:=i-1; if suma(t,k) then back(k,t+1); end; end;
6
begin readln(n); nr:=0; for dim:=1 to n do back(dim,1); writeln('Submultimile sunt:'); for k:=1 to nr do begin for j:=1 to n do if tot[k][j]=1 then write(j,' '); writeln; end; end.
Problema 6 Să se realizeze un unit care să cuprindă subprograme pentru: a) calculul vectorului medie pentru o selecţie dată de vectori aleatori; b) calculul matricei de covarianţă pentru o selecţie dată de vectori aleatori; c) calculul matricei de autocorelaţie pentru o selecţie dată de vectori aleatori; d) determinarea valorilor şi vectorilor proprii corespunzători matricei de covarianţă calculată pe o selecţie dată de vectori aleatori. Soluţie Fie X un vector aleator cu medie µ şi matrice de covarianţă Σ , {X1, X 2,..., Xm} o selecţie bernoulliană de volum m asupra lui X. •
∑ =
media de selecţie se calculează astfel: µ =
1 m
m
∑X
i
;
i=1
•
matricea de covarianţă de selecţie se calculează după formula:
1
m
∑ (X m− 1
T
i
− µ)( Xi − µ) ;
i= 1
•
matricea de autocorelaţie de selecţie este dată prin formula: S =
1
m
∑XX m i
T i
= ∑ + µµ T ;
i=1
• cum matricea de covarianţă de selecţie este simetrică şi pozitiv definită, rezultă că se poate aplica algoritmul lui Jacobi [citarea algoritmului]; valorile proprii vor fi reale, pozitive, iar vectorii proprii vor avea cu componente reale. Unit-ul complet este:
unit stat; interface type vect_ra=array[1..30] of real; selectie=array[1..50] of vect_ra; matrice=array[1..30,1..30] of real; procedure media(var s:selectie; var med:vect_ra;dim_v,vol_sel:byte); procedure covarianta(var s:selectie;var sigma:matrice;dim_v,vol_sel:byte); procedure autocorelatie(var s:selectie;var auto:matrice;dim_v,vol_sel:byte); procedure vect_val_pr(var sel:selectie;var val_pr:vect_ra; var vect_pr: matrice; dim_v, vol_sel:byte; eps:real; itmax:word);
7
implementation procedure media; var i,j:byte; begin for i:=1 to dim_v do begin med[i]:=0; for j:=1 to vol_sel do med[i]:=med[i]+s[j][i]; med[i]:=med[i]/vol_sel; end; end; procedure covarianta; var i,j,k:byte; medie:vect_ra; begin media(s,medie,dim_v,vol_sel); for i:=1 to dim_v do for j:=1 to dim_v do begin sigma[i,j]:=0; for k:=1 to vol_sel do sigma[i,j]:=sigma[i,j]+(s[k][i]-medie[i])*(s[k][j]-medie[j]); sigma[i][j]:=sigma[i,j]/(vol_sel-1); end; end; procedure autocorelatie; var i,j,k:byte; begin for i:=1 to dim_v do for j:=1 to dim_v do begin auto[i,j]:=0; for k:=1 to vol_sel do auto[i,j]:=auto[i,j]+s[k][i]*s[k][j]; auto[i][j]:=auto[i,j]/vol_sel; end; end; procedure vect_val_pr; var i,it,j,k:byte; aii,aji,ajj,amax,c,c1,s,t,inter,inter1:real;
8
sigma:matrice; begin it:=0; covarianta(sel,sigma,dim_v,vol_sel); for i:=1 to dim_v do begin for j:=1 to dim_v do vect_pr[i][j]:=0; vect_pr[i][i]:=1; val_pr[i]:=sigma[i,i]; end; amax:=1; while((amax>eps)and(iteps) then begin c:=0.5*(aii-ajj)/sigma[j,i]; t:=1/(abs(c)+sqrt(1+c*c)); if c<0 then t:=-t; c:=1/sqrt(1+t*t);s:=c*t; for k:=1 to i-1 do begin t:=sigma[i,k]*c+sigma[j,k]*s; sigma[j,k]:=sigma[j,k]*c-sigma[i,k]*s; sigma[i,k]:=t; end; for k:=i+1 to j-1 do begin t:=sigma[k,i]*c+sigma[j,k]*s; sigma[j,k]:=sigma[j,k]*c-sigma[k,i]*s; sigma[k,i]:=t; end; for k:=j+1 to dim_v do begin t:=sigma[k,i]*c+sigma[k,j]*s; sigma[k,j]:=sigma[k,j]*c-sigma[k,i]*s; sigma[k,i]:=t; end; for k:=1 to dim_v do begin t:=vect_pr[k,i]*c+vect_pr[k,j]*s;
9
end;
vect_pr[k,j]:=vect_pr[k,j]*c-vect_pr[k,i]*s; vect_pr[k,i]:=t; end; t:=2*s*c*sigma[j,i]; val_pr[i]:=aii*c*c+ajj*s*s+t; val_pr[j]:=aii*s*s+ajj*c*c-t; sigma[j,i]:=0; end;
end; for i:=1 to dim_v-1 do for j:=i+1 to dim_v do if(val_pr[i]
10
program gaussexp; uses crt; var csi,o,z,z0:real; i:integer; procedure norm01(var z:real); var suma:real; i:integer; begin suma:=0; for i:=1 to 12 do suma:=suma+random; suma:=suma-6; z:=suma; end; begin clrscr; randomize; for i:=1 to 100 do begin readln(o); norm01(z0); norm01(csi); z:=o*z0+sqrt(1-o*o)*csi; writeln(z); end; end. {**** Acest program va genera procesul gaussian cu functie de autocorelatie algoritmul clasic ****} program gauss;
uses crt; var v:array[1..100] of real; x,a:real; i,n,p:integer; begin clrscr; randomize; readln(a,n,p); for i:=1 to n do v[i]:=random; for i:=1 to n-p do v[i]:=v[i+p]; x:=0; for i:=1 to n-p do x:=x+v[i]; for i:=1 to p do v[n-p+i]:=-a+2*a*random;
11
liniara folosind
for i:=n-p+1 to n do x:=x+v[i]; for i:=1 to n do write(' ',v[i]); end. {**** Acest program va genera procese Poisson in cerc care vor fi salvate in fisierul as.txt ****}
program gener; uses crt; var f1:text; q,u1,v:real; i,n,j,l:integer; function fp(m:real):integer; var u,s,p:real; k:integer; begin k:=0;p:=exp(-m); u:=random; s:=p; while u>s do begin k:=k+1; p:=p*m/k; s:=s+p; end; fp:=k; end; begin writeln('Dati q '); readln(q); writeln('Dati numarul generarilor '); readln(l); assign(f1,'as.txt'); rewrite(f1); randomize; for j:=1 to l do begin n:=fp(q*3.14); writeln(n); for i:=1 to n do begin repeat u1:=2*random-1; v:=2*random-1; until u1*u1+v*v<=1; writeln(f1,' ',u1,' ',v);
12
end; end; close(f1); writeln; end.
{**** Acest program genereaza numere aleatoare conform algoritmului clasic Gsalca cu repartitia de intrare exponentiala avand cealalta functie de intrare cea data de functia fct de mai jos ****}
program Gslaca; uses crt; var x,y,s:real; z:array[1..2] of real; i:integer; procedure expon(var x:real); begin x:=-ln(random)/0.3; end; function fct(x:real):real; begin fct:=1.2/(1+exp(-x)) end; begin randomize; clrscr; s:=0; repeat for i:=1 to 2 do begin expon(x); z[i]:=1-fct(x) end; s:=s+random; if (z[i]>1) then exit else begin y:=(1-z[i])/z[i]; x:=y*x; end; writeln(x) ;write(#7); until (readkey='q') or (s>4); end. {**** Acest program genereaza o stare a unui lant Markov omogen cu doua stari, de ordinul intai, data fiind matricea de trecere P[i,j], 1<=i,j<=2 ****}
program Markov;
13
uses crt; var a,b:real; F,P:array[1..2,1..2] of real; i,j,k:integer; suma,U:real; begin clrscr; readln(a); readln(b); if((a>=1)or(a<=0)or(b>=1)or(b<=0)) then begin writeln('Date incorecte!'); exit; end; P[1,1]:=a;P[1,2]:=1-a; P[2,1]:=1-b;P[2,2]:=b; for i:=1 to 2 do begin suma:=0; for j:=1 to 2 do begin for k:=1 to j do suma:=suma+P[i,k]; F[i,j]:=suma; end; end; j:=1; randomize; U:=random; i:=1; while (F[i,j]<=U) do j:=j+1; writeln('S-a generat starea ',j-1); end. program poisson1;
{***** Acest program genereaza un proces Poisson 1-dimensional omogen pe segmentul (0,x0] *****}
uses crt; var l,x0,x:real; n:integer; begin clrscr; randomize; readln(l,x0); x:=0;n:=0; while x<=x0 do
14
end; end.
begin x:=x-(1/l)*ln(1-random); n:=n+1; writeln(x,' ',n);
program poisson2; {***** Acest program genereaza un proces Poisson 2-dimensional omogen pe dreptunghiul (0,x0] (0,y0] *****}
uses crt; var l,x0,x,y0,y:real; n:integer; begin clrscr; randomize; readln(l,x0,y0); x:=0;n:=0; while x<=x0 do begin x:=x-(1/l)*ln(1-random); y:=random*y0; n:=n+1; writeln(x,' ',y,' ',n); end; end.
15
EXERCIŢII DIVERSE Exerciţiul 1 Să se determine dacă un număr introdus de la tastatură este prim sau nu. Soluţie: Condiţia suficientă ca un număr n să fie prim este ca acesta să nu se dividă cu nici un alt număr din intervalul 1..[ ]. n
program nr_prim; uses crt; var n:word; a:real; i,m:word; prim:boolean; begin clrscr; write('Introduceti numarul pentru test '); readln(n); prim:=true; a:=n; m:=trunc(sqrt(a)); i:=2; while(i<=m) and prim do if (n mod i) = 0 then prim:=false else i:=i+1; if prim then writeln('Numarul este prim') else writeln('Numarul nu este prim'); readln; end.
Exerciţiul 2 Să se determine suma şi produsul a două polinoame. Soluţie: Fie polinoamele p1, p2 cu deg(pi)=gradi, i=1..2 şi grad=max(grad1, grad2). Suma celor două polinoame se calculează după formula: suma[k]= p1[k]+p2[k], k=1..grad (dacă unul din gradele celor două polinoame este strict inferior lui grad, coeficienţii “lipsă” sunt 0). Produsul celor două polinoame se calculează după formula: k
produs [ k ] = ∑ p1 [l] ⋅ p 2 [ k − l] , k=0..grad1+grad2. l =0
Polinoamele sunt reprezentate prin vectorii coeficienţilor cores-punzători. Gradele polinoamelor, precum şi coeficienţii corespunzători vor fi introduşi de la tastatură. program polinoame; uses crt; var p1,p2,suma,produs:array[0..40] of integer; i,j,grad1,grad2,grad: integer; procedure sumapol; var k:integer; begin for k:=0 to grad do
16
suma[k]:=p1[k]+p2[k]
end; procedure produspol; var k,l,prod:integer; begin for k:=0 to grad1+grad2 do begin prod:=0; for l:=0 to k do prod:=prod+p1[l]*p2[k-l]; produs[k]:=prod end end; {programul principal} begin clrscr; write('Dati gradul maxim al polonmului1 '); readln(grad1); write('Dati coeficientii primului polinom '); for i:=0 to grad1 do readln(p1[i]); write('Dati gradul maxim al celui de-al doilea polinom'); readln(grad2); write('Dati coeficientii celui de-al doilea polinom '); for i:=0 to grad2 do read(p2[i]); if grad1>grad2 then grad:= grad1 else grad:=grad2; sumapol; produspol; writeln('Suma polinoamelor este: '); for i:=0 to grad-1 do if( suma[i+1]>=0)then write(suma[i],'*X^',i,'+') else write(suma[i],'*X^',i); writeln(suma[grad],'*X^',grad); writeln('Produsul polinoamelor este: '); for i:=0 to grad1+grad2-1 do if( produs[i+1]>=0)then write(produs[i],'*X^',i,'+') else write(produs[i],'*X^',i); writeln(produs[grad1+grad2],'*X^',grad1+grad2); end.
Exerciţiul 3 Să se genereze toate permutările mulţimii {1, 2,..., n}, unde n este un număr natural citit de la tastatură, n ≤ 7. Soluţie: Problema va fi rezolvată utilizându-se metoda backtracking . Forma standard a acestei metode se aplică problemelor în care trebuie găsit un vector x=(x1, x2, ..., xn) din spaţiul soluţiilor S=S1× S2× ...× Sn unde, pentru orice 1≤ i ≤ n, Si = si (număr finit de elemente) şi pe Si este definită o relaţie de ordine, iar x reprezintă soluţia rezultat satisfăcând condiţiile interne corespunzătoare problemei. Ca variante de ieşiri sunt posibile cazurile: o singură soluţie rezultat, toate soluţiile rezultat (în probleme de generare asemănătoare celei propuse), o soluţie rezultat care optimizează (minim sau maxim) un criteriu f:S→R. Construcţia unei soluţii se face astfel: • se presupun determinate la momentul curent x1, x2, ..., xk ; • dacă secvenţa anterior calculată satisface condiţiile de continuare specifice problemei (dacă există şansa de a se obţine o soluţie rezultat) se alege xk+1 ∈ Sk+1
17
• • .
altfel, dacă xk are succesor în Sk , xk ← succ(xk ) altfel, dacă xk nu are succesor în Sk , se procedează în aceeaşi manieră cu “resatisfacerea” lui xk-
1
Procedura generală de calcul este următoarea: procedure back(k:byte); begin if k=n+1 then final else begin x[k]:=init(k); while succ(k) do if continuare(k) then back(k+1); end; end;
în care:
• final este o procedură specifică momentului în care s-a determinat o soluţie rezultat x (se afişează rezultatul, se testează o funcţie criteriu pentru soluţia obţinută, aceasta selectându-se doar în anumite condiţii de optim ş.a.m.d.); • init(k) este o funcţie de iniţializare a lui xk cu predecesorulu primului element din Sk ; • succ(k) este o funcţie booleană care testează existenţa succesorului lui xk în Sk şi, dacă acest lucru este posibil, se înlocuieşte xk cu succesorul lui din Sk ; • continuare(k) este o funcţie booleană care testează condiţiile de continuare (dacă secvenţa determinată până la momentul curent poate duce la o soluţie rezultat). În continuare este prezentată problema generării tuturor permutărilor mulţimii {1, 2,..., n} aplicânduse exact metoda generală şi ţinându-se cont de următoarele aspecte: • S1 = S2 = ... = Sn = {1, 2,..., n} (deci funcţia init nu depinde de nici un parametru, întorcând valoarea 0 indiferent de indicele elementului de iniţializat); • condiţia ca secvenţa {x1, x 2,..., xk } să fie una corectă pentru a se iniţia generarea lui xk+1 (ştiind că {x1, x2,..., xk-1} este corectă) este cea dată de definiţia unei permutări: xk ∉ {x1, x2,..., xk-1}. Programul Pascal este: program permutare; uses crt; type tip_elem=0..7; var x:array[1..7] of tip_elem; n:byte; function init:byte; begin init:=0; end; function succ(k:byte):boolean; begin succ:=x[k]
18
while(ix[k]) do inc(i); continuare:=i=k; end; procedure final; var i:byte; begin for i:=1 to n do write(x[i],' '); readln; end; procedure back(k:byte); begin if k=n+1 then final else begin x[k]:=init; while succ(k) do if continuare(k) then back(k+1); end; end; begin clrscr; write('Numarul de elemente al permutarii: '); readln(n); back(1); end. După cum se poate remarca, unele din operaţiile precedente (cum ar fi funcţia init , lucrul cu funcţia succ în condiţiile în care S1 = S2 = ... =Sn = {1, 2,..., n}) pot fi reformulate într-o manieră ce simplifică scrierea programului. De exemplu, o altă variantă corectă de rezolvare este: program permutare_1; uses crt; type tip_elem=0..7; var x:array[1..7] of tip_elem; n:byte; procedure final; var i:byte; begin for i:=1 to n do write(x[i],' '); readln; end; function continuare(k:byte):boolean; var i:byte; begin i:=1; while(ix[k]) do inc(i); continuare:=i=k; end; procedure back(k:byte);
19
var i:byte; begin if k=n+1 then final else for i:=1 to n do begin x[k]:=i; if continuare(k) then back(k+1); end; end; begin clrscr; write('Numarul de elemente al permutarii: '); readln(n); back(1); end.
Exerciţiul 4 Să se scrie programul Pascal pentru generarea tuturor submulţimilor mulţimii {1, 2,..., n}, unde n este un număr natural citit de la tastatură, n ≤ 10. Soluţie: Se vor genera, prin metoda backtracking, toate submulţimile cu k elemente, 1 ≤ k ≤ n. Modul de reprezentare a unei submulţimi SubS a lui S (privite ca vectori) este: SubS [ i ] = 0, S [ i ]∉ SubS 1, S [ i ]∈ SubS ¿ ¿ {¿ ¿ ¿ Condiţiile de continuare sunt cele ce caracterizează o submulţime a unei mulţimi, momentul terminării generării unei soluţii - o submulţime cu k elemente - sesizându-se când suma elementelor vectorului generat este k. În momentul determinării unei submulţimi, aceasta este trecută într-un vector, generându-se astfel P({1, 2,..., n}). Programul Pascal este: program submultime; type elem=0..1; sub=array[1..10] of elem; var n,dim:byte; x:sub; tot:array[1..200] of sub; k,j:integer; nr:byte; function suma(t,k:byte):boolean; var s,i:byte; begin s:=0; for i:=1 to t do s:=s+x[i]; if s<=k then suma:=true
20
else suma:=false; end; function sumaf:byte; var s,i:byte; begin s:=0; for i:=1 to n do s:=s+x[i]; sumaf:=s; end; procedure back(k,t:byte); var i:byte; begin if (t=n+1) then if(sumaf=k) then begin inc(nr); for i:=1 to n do tot[nr][i]:=x[i]; end else else for i:=2 downto 1 do begin x[t]:=i-1; if suma(t,k) then back(k,t+1); end; end; begin readln(n); nr:=0; for dim:=1 to n do back(dim,1); writeln('Submultimile sunt:'); for k:=1 to nr do begin for j:=1 to n do if tot[k][j]=1 then write(j,' '); writeln; end; end.
Exerciţiul 5 Să se realizeze o unitate Pascal care să cuprindă subprograme pentru rezolvarea următoarelor operaţii: calculul vectorului medie pentru o selecţie dată de vectori aleatori; calculul matricei de covarianţă pentru o selecţie dată de vectori aleatori; calculul matricei de autocorelaţie pentru o selecţie dată de vectori aleatori;
21
determinarea valorilor şi vectorilor proprii corespunzători matricei de covarianţă calculată pe o selecţie dată de vectori aleatori. Soluţie: Fie X un vector aleator cu medie µ şi matrice de covarianţă Σ , {X1, X2,..., Xm} o selecţie bernoulliană de volum m asupra lui X.
•
media de selecţie se calculează astfel: µ =
•
∑ˆ
=
1
matricea m
∑ ( X − µˆ ) ( X − µˆ )
m − 1 i=1
•
de
i
i
covarianţă T
de
1 m
m
∑X
i
;
i=1
selecţie
se
calculează
după
formula:
;
matricea de autocorelaţie de selecţie este dată prin formula: S =
1
m
∑XX m i
T i
= ∑ + µµ T ;
i=1
• cum matricea de covarianţă de selecţie este simetrică şi pozitiv definită, rezultă că se poate aplica algoritmul lui Jacobi [citarea algoritmului]; valorile proprii vor fi reale, pozitive, iar vectorii proprii vor avea componente reale. Unitatea completă este: unit stat; interface type vect_ra=array[1..30] of real; selectie=array[1..50] of vect_ra; matrice=array[1..30,1..30] of real; procedure media(var s:selectie; var med:vect_ra;dim_v,vol_sel:byte); procedure covarianta(var s:selectie;var sigma:matrice;dim_v,vol_sel:byte); procedure autocorelatie(var s:selectie;var auto:matrice;dim_v,vol_sel:byte); procedure vect_val_pr(var sel:selectie;var val_pr:vect_ra; var vect_pr: matrice; dim_v, vol_sel:byte; eps:real; itmax:word); implementation procedure media; var i,j:byte; begin for i:=1 to dim_v do begin med[i]:=0; for j:=1 to vol_sel do med[i]:=med[i]+s[j][i]; med[i]:=med[i]/vol_sel; end; end; procedure covarianta; var i,j,k:byte; medie:vect_ra; begin
22
media(s,medie,dim_v,vol_sel); for i:=1 to dim_v do for j:=1 to dim_v do begin sigma[i,j]:=0; for k:=1 to vol_sel do sigma[i,j]:=sigma[i,j]+ (s[k][i]-medie[i])*(s[k][j]-medie[j]); sigma[i][j]:=sigma[i,j]/(vol_sel-1); end; end; procedure autocorelatie; var i,j,k:byte; begin for i:=1 to dim_v do for j:=1 to dim_v do begin auto[i,j]:=0; for k:=1 to vol_sel do auto[i,j]:=auto[i,j]+s[k][i]*s[k][j]; auto[i][j]:=auto[i,j]/vol_sel; end; end; procedure vect_val_pr; var i,it,j,k:byte; aii,aji,ajj,amax,c,c1,s,t,inter,inter1:real; sigma:matrice; begin it:=0; covarianta(sel,sigma,dim_v,vol_sel); for i:=1 to dim_v do begin for j:=1 to dim_v do vect_pr[i][j]:=0; vect_pr[i][i]:=1; val_pr[i]:=sigma[i,i]; end; amax:=1; while((amax>eps)and(iteps) then
23
end;
begin c:=0.5*(aii-ajj)/sigma[j,i]; t:=1/(abs(c)+sqrt(1+c*c)); if c<0 then t:=-t; c:=1/sqrt(1+t*t);s:=c*t; for k:=1 to i-1 do begin t:=sigma[i,k]*c+sigma[j,k]*s; sigma[j,k]:=sigma[j,k]*c-sigma[i,k]*s; sigma[i,k]:=t; end; for k:=i+1 to j-1 do begin t:=sigma[k,i]*c+sigma[j,k]*s; sigma[j,k]:=sigma[j,k]*c-sigma[k,i]*s; sigma[k,i]:=t; end; for k:=j+1 to dim_v do begin t:=sigma[k,i]*c+sigma[k,j]*s; sigma[k,j]:=sigma[k,j]*c-sigma[k,i]*s; sigma[k,i]:=t; end; for k:=1 to dim_v do begin t:=vect_pr[k,i]*c+vect_pr[k,j]*s; vect_pr[k,j]:=vect_pr[k,j]*cvect_pr[k,i]*s; vect_pr[k,i]:=t; end; t:=2*s*c*sigma[j,i]; val_pr[i]:=aii*c*c+ajj*s*s+t; val_pr[j]:=aii*s*s+ajj*c*c-t; sigma[j,i]:=0; end;
end; for i:=1 to dim_v-1 do for j:=i+1 to dim_v do if(val_pr[i]
24
Exerciţii propuse 1. Să se scrie programul Pascal pentru determinarea celui mai mic multiplu comun al n numere. 2. Să se scrie un subprogram Pascal pentru a decide dacă două numere naturale sunt prime între ele. 3. Să se scrie programul Pascal pentru generarea tuturor numerelor prime mai mici decât n, n citit de la tastatură. 4. Să se scrie un subprogram Pascal pentru calculul celui mai mare divizor comun a n numere naturale, n≥ 3. 5. Să se scrie un subprogram Pascal pentru descompunerea unui număr natural în factori primi. 6. Să se scrie programul Pascal pentru generarea tuturor combinărilor de k elemente ale unei mulţimi de n elemente, n≥ k . 7. Să se scrie un subprogram Pascal pentru calculul valorii unui polinom într-un punct dat. 8. Să se scrie un subprogram Pascal pentru calculul derivatei unui polinom. 9. Să se scrie un subprogram Pascal pentru determinarea compunerii a două polinoame. 10. Utilizând algoritmul lui Euclid, să se scrie subprogramele Pascal pentru determinarea celui mai mare divizor comun şi a celui mai mic multiplu comun pentru două polinoame. 11. Să se realizeze programul Pascal pentru calculul polinomului de interpolare Lagrange, pentru un set de perechi {(x1,y1),(x2,y2),…,(xn, yn)}, citite de la tastatură.
25
Exercitiul 1. Sa se scrie un program care citeste un text (maxim 255 caracter) de la tastatura si il afiseaza compactat, prin eliminarea spatiilor suplimentare. Rezolvare: Necesitatea compactarii apare in trei situatii diferite: exista caractere spatiu la inceputul textului sau la sfirsitul sau (acestea se vor elimina in totalitate) sau exista mai mult de un caracte intre cuvinte, caz in care se va pastra numai un caracter, restul eliminindu-se. Prin cuvint se intelege un subsir de caractere intre care nu exista nici un spatiu. Algoritmul parcurge sirul intr-o bucla WHILE-DO, verificind fiecare caracter; daca nu este spatiu se trece la caracterul urmator (caracterul curent este indicat de contorul i); daca caracterul curent este spatiu trebuie trebuie sa decidem daca il eliminam sau il pastram. Caracterul trebuie eliminat daca este primul din sir, ultimul din sir sau desparte doua cuvinte iar urmatorul caracter este tot spatiu. Iesirea din bucla se petrece atunci cind contorul I are o valoare mai mare decit lungimea sirului (indica un carater aflat 'dincolo' de sfirsitul sirului). Daca decidem sa pastram spatiul, se trece la urmatorul caracter, prin incrementarea contorului i. Daca dorim sa eliminam caracterul se procedeaza astfel: 1) toate caracterele care urmeaza in sir vor fi mutate cu o pozitie spre inceputul sirului; 2) se inscrie in s[0] noua lungime a sirului (cu 1 mai mica decit cea anterioara).
program compactare_sir; var s:string; i,j,l:byte; begin write('Textul de compactat: '); readln(s); l:=length(s); i:=1; while i<=l do begin if s[i]<>' ' then inc(i) else begin if (i=1) or (i=l) or (s[i+1]=' ') then begin for j:=i to l-1 do s[j]:=s[j+1]; dec(l); s[0]:=chr(l); end else inc(i); end; end; writeln(s); readln; end. Exemplu de rulare: Textul de compactat: Acesta este un exemplu de compactare a unui text Acesta este un exemplu de compactare a unui text .
26
.
Exercitiul 2. Sa se scrie un program care numara cuvintele dintr-un text. Rezolvare: se considera ca textul nu este compactat. Algoritmul presupune parcurgerea textului caracter cu caracter si incrementarea unui contor (initializat cu 0) atunci cind se detecteaza inceputul unui nou cuvint. Avem inceput de cuvint atunci cind dupa un spatiu urmeaza un caracter diferit de spatiu.
program numara_cuvinte; var s:string; i,n,l:byte; begin write('Textul de prelucrat:'); readln(s); l:=length(s); n:=0; for i:=1 to l-1 do if (s[i]=' ') and (s[i+1]<>' ') then inc(n); writeln('Textul contine ',n,' cuvinte.'); readln; end. Exemplu de rulare: Textul de prelucrat: Programul va numara Textul contine 6 cuvinte.
cuvintele acestui text.
Exercitiul 3. Sa se relizeze un program care introduce cite un spatiu intre fiecare 2 caractere diferite de spatiu ale unui sir citit de la tastatura. Observatie: sirul initial va avea maxim 122 caractere pentru a evita problemele legate de depasirea lungimii maxime a unui sir. Rezolvare: Vom trata sirul de caractere tot ca vector. Intr-o bucla WHILE-DO se va parcurge sirul caracter cu caracter pina cind contorul va depasi sfirsitul acestuia. Daca intilnim doua caractere, ambele diferite de spatiu, se mareste lungimea sirului cu 1, se deplaseaza restul sirului spre dreapta cu o pozitie (spre sfirsitul sirului) iar in pozitia i+1 (deci intre cele 2 caractere detectate anterior) se inscrie un caracter spatiu.
program extindere; var s:string; l,i,j:byte; begin write('Sirul initial: '); readln(s); l:=length(s); i:=1; while i<=l do begin if (s[i]<>' ') and (s[i+1]<>' ') then begin l:=l+1;
27
s[0]:=chr(l); for j:=l downto i+2 do s[j]:=s[j-1]; s[i+1]:=' '; i:=i+2; end else i:=i+1;
end; writeln(s); readln; end.
Exemplu de rulare: Sirul initial: aaa bbb c c c c c a aa bb b c c c cc
Exercitiul 4. Sa se scrie un unit cu subprograme care realizeaza urmatoarele prelucrari: 1. codificarea/decodificarea unui sir de caractere prin metoda ROT13; 2. codificarea/decodificarea unui sir prin interschimbarea grupurilor de 4 biti; 3. contorizarea numarului de aparitii ale fiecarul caracter ASCII intr-un sir. Rezolvare: 1. Metoda ROT13 presupune rotirea setului de caractere ASCII cu 13 pozitii. Astfel litera A devine N, B devine O, a devine n si asa mai departe. Algoritmul presupune parcurgerea sirului intr-o bucla FOR-DO si inlocuirea fiecarui caracter cu caracterul care are codul ASCII mai mare cu 13. Daca se depaseste valoarea maxima (255) - adica se trece dincolo de sfirsitul setului ASCII - se reia numaratoarea de la inceputul setului. Decodificare este asemanatoare, cu diferenta ca se inlocuiesc caracterele cu cele care au, respectiv, codul ASCII cu 13 mai mic. Procedurile primesc ca parametru sirul care trebuie (de)codificat. 2. Pentru interschimbarea grupurilor de 4 biti (superior si inferior)dintr-un caracter se pot folosi operatiile pe biti (logice si de deplasare). Deoarece aceste operatii se efectueaza pe operanzi numerici, vom suprapune un vector cu elemente de tip byte peste sirul de codificat/decodificat si vom lucra cu acesta. Prin operatii de deplasare (shl si shr) se separa cele doua grupuri de cite 4 biti in doua variabile auxiliare, de tip byte. Folosind convenabil operatia de deplasare, grupurile de biti sint deja in pozitia finala. Ultima operatie consta in suprapunerea celor doua grupuri printr-o operatie sau pe biti. Procedurile primesc ca parametru sirul care trebuie (de)codificat. Exemplu: 1011011 00001011 01110000 => 00001011 01110000 01111011 3. Pentru numararea aparitiilor fiecarui caracter intr-un sir se foloseste un vector initializat cu valori nule, cu atitea elemente cite caractere are setul ASCII. Fiecare element al vectorului va contoriza aparitiile caracterului cu codul ASCII corespunzator (astfel elementul cu numarul 64 va arata
28
numarul aparitiilor caracterului A, 65 pentru B etc.). Intr-o bucla FOR-DO se parcurge sirul si, pentru fiecare caracter este incrementat elementul corespunzator din vector (dat de codul ASCII al caracterului, disponibil prin apelarea functiei ORD).
unit codif; interface type vector=array[0..255]of byte; const hi=$f0; lo=$0f; procedure codrot13(var s:string); procedure decodrot13(var s:string); procedure codec4b(var s:string); procedure contor(s:string; var nr:vector); implementation procedure contor(s:string; var nr:vector); var i:byte; begin for i:=0 to 255 do nr[i]:=0; for i:=1 to length(s) do inc(nr[ord(s[i])]); end; procedure codec4b(var s:string); var c,d:byte; i:byte; x:array[0..255]of byte absolute s; begin for i:=1 to length(s) do begin c:=x[i] shl 4; d:=x[i] shr 4; x[i]:=c or d; end; end; procedure codrot13(var s:string); var i:byte; begin for i:=1 to length(s) do s[i]:=chr((ord(s[i])+13) mod 255); end; procedure decodrot13(var s:string); var i:byte; begin for i:=1 to length(s) do s[i]:=chr((255+ord(s[i])-13) mod 255); end; end.
29
Exemplu de program apelator:
program apel; uses codif; var s:string; x:vector; i,k:byte; begin write('Sirul de prelucrat: '); readln(s); write(‘Sirul de prelucrat: '); writeln('Codificare/decodificare ROT13:'); codrot13(s); writeln(s); decodrot13(s); writeln(s); writeln(‘'Codificare/decodificare 4b:'); codec4b(s);writeln(s); codec4b(s);writeln(s); writeln('Statistica caractere:'); contor(s,x); k:=1; for i:=0 to 255 do begin if x[i]<>0 then begin write(chr(i):1,' - ',x[i]:2,' '); inc(k); end; if k mod 7=0 then writeln(' '); end; readln; end. Exemplu de rulare:
Exercitiul 5. Sa se scrie un subprogram care insereaza intr-un sir un alt sir in pozitia imediat urmatoare primei apariti a unui caracter dat; daca acesta nu este gasit atunci inserarea se face la sfirsit. Rezolvare: Primul pas este determinarea pozitiei in care se va insera al doilea sir. In acest scop se parcurge sirul initial intr-o bucla WHILE-DO pina la detectarea caracterului dupa care se insereaza. La iesirea din bucla variabila i va indica pozitia caracterului dupa care se insereaza; adaugind 1 obtinem pozitia in care se insereaza. Pasul urmator consta in inscrierea noii lungimi a sirului (lungimea initiala + lungimea sirului care se insereaza) in pozitia 0. Caracterele din pozitia i pina la sfirsitul sirului initial trebuie deplasate la dreapta pentru a face loc sirului care se insereaza. Ultimul pas este copierea caracterelor sirului de inserat in sirul initial, din pozitia i.
30
procedure inser(var s:string;ss:string;c:char); var i,j,l,ll:byte; vb:boolean; begin i:=1; vb:=false; l:=length(s);ll:=length(ss); while (i
Exercitiul 6: Sa se scrie un subprogram care sterge dintr-un sir un subsir dat (prima aparitie a subsirului). Rezolvare: pentru a pute sterge subsirul, acesta trebuie intii localizat in sirul initial. Daca notam cu l lungimea sirului initial si cu ll lungimea subsirului de sters, atunci inceputul acestuia poate fi oriunde intre pozitia 1 si l-ll in sirul initial. Se parcurge sirul s intr-o bucla WHILE-DO pina cind se depaseste pozitia l-ll sau a fost detectat si sters subsirul dat. O posibila aparitie a subsirului este luata in calcul atunci cind caracterul curent din s este identic cu primul caracter din subsirul de sters (ss). Atunci cind se intilneste o astfel de situatie se verifica daca intr-adevar s-a intilnit subsirul ss; pentru aceasta se compara caracter cu caracter sirul s, din pozitia curenta, pe o lungime ll cu subsirul ss. Daca nu se intilneste nici o diferenta se sterge subsirul si se marcheaza prin variabila booleana vb terminarea prelucrarilor. Pentru stergere se deplaseaza toate caracterele ramase din sirul s, din pozitia curenta+ll, cu ll pozitii la stinga si se inscrie noua lungime a sirului s in pozitia s[0].
procedure sterg(var s:string; ss:string); var i,j,l,ll:byte; vb,vb1:boolean; begin l:=length(s); ll:=length(ss); vb:=false; i:=1; while (i<=l-ll) and (not vb) do
31
end;
begin if s[i]<>ss[1] then inc(i) else begin vb1:=true; for j:=1 to ll do if ss[j]<>s[i+j-1] then vb1:=false; if vb1 then begin vb:=true; for j:=i+ll to l do s[j-ll]:=s[j]; s[0]:=chr(l-ll); end else inc(i); end; end;
Exemplu de rulare: Sir initial: Acesta este sirul de test Subsir: sta este si Acerul de test
Exercitiul 7. {Sa se scrie un subprogram care numara aparitiile unui subsir intr-un sir de caractere dat. Nu este obligatoriu ca aparitiile subsirului sa fie disjuncte. Rezolvare: Se parcurge sirul initial, s, pentru a detecta posibile aparitii ale subsirului de cautat. In acest scop se cauta primul caracter al subsirului, intre pozitia 1 si l-ll din sirul initial, unde l este lungimea sirului initial iar ll lungimea subsirului. Daca se intilneste o egalitate, atunci se verifica daca intr-adevar s-a detectat subsirul cautat, prin compararea caracter cu caracter, din pozitia curenta, pe o lungime de l caractere, cu sirul de cautat. Daca nu se intilnesc diferente, se incrementeaza numarul de aparitii detectate ale sirului ss.
procedure nr_apar(s,ss:string;var nr:byte); var i,j,l,ll:byte; var vb:boolean; begin l:=length(s); ll:=length(ss); nr:=0; for i:=1 to l-ll+1 do begin if s[i]=ss[1] then begin vb:=true; for j:=1 to ll-1 do if s[i+j]<>ss[j+1] then vb:=false; if vb then inc(nr); end; end;
32
end; Exemplu de rulare: Sirul initial: asasadfasdasdasadfg Sir de cautat: asa Nr. aparitii: 3
Exercitii propuse: Sa se scrie un subprogram care sa inlocuiasca intr-un sir dat toate aparitiile unui subsir cu un alt sir de caractere. Sa se scrie un subprogram care transforma caracterele unui text astfel incit prima litera din fiecare fraza sa fie majuscula iar restul litere mici. Frazele se incheie cu caracterul punct. Sa se scrie un subprogram care transforma toate caracterele majuscule dintr-un text in litere mici si invers. Sa se scrie un subprogram care transforma un sir de caractere in valoare numerica. Daca nu este posibila conversia se va semnala eroare. Sa se scrie un subprogram care transforma un numar in sirul de caractere corespondent. Sa se scrie un subprogram care anagrameaza un sir de caractere (un cuvint). Sa se scrie un subprogram care cauta cel mai lung subsir sortat crescator intr-un sir dat.
33
LUCRUL CU MASIVE DE DATE Exerciţiul 1 Să se proiecteze o unitate Pascal care să conţină subprograme pentru rezolvarea următoarelor probleme: reuniunea a două mulţimi; intersecţia a două mulţimi; diferenţa dintre două mulţimi; produsul cartezian dintre două mulţimi. Soluţie: a) Operaţia de reuniune dintre două mulţimi A şi B se defineşte astfel: A∪B= {xx∈A sau x∈B} Cunoscută sub numele “interclasare cu selecţie”, operaţia de reuniune presupune parcurgerea secvenţială a mulţimilor iniţiale şi trecerea în mulţimea rezultat a elementelor care se regăsesc în cele două mulţimi, fiecare luat o singură dată. b) Intersecţia dintre două mulţimi A şi B se defineşte astfel: A∩B= {xx∈A şi x∈B} În urma apelului procedurii Intersectie va fi obţinută o mulţime cu elementele comune mulţimilor iniţiale. Dacă intersecţia este mulţimea vidă, atunci cardinalul mulţimii rezultat este 0 (parametrul card ). c) Diferenţa dintre două mulţimi A şi B se defineşte, în sens matematic, astfel: A\B= {xx∈A şi x∉B}. d) Produsul cartezian dintre două mulţimi A şi B se defineşte ca fiind mulţimea perechilor ordonate (x,y), cu proprietatea că x∈A şi y∈B: AxB= {(x,y)x∈A şi y∈B}. Observaţie: Pentru rezolvarea problemei propuse, unitatea conţine subprograme corespunzătoare operaţiilor prezentate anterior (reuniune, intersecţie, diferenţă şi produs cartezian). Se utilizează două proceduri interne pentru sortarea elementelor unui vector respectiv pentru compactarea elementelor unui vector. Prin compactare se asigură unicitatea valorilor elementelor din mulţimile iniţiale. Unitatea Pascal: unit multimi; interface type multime=array[1..50] of integer; produs=array[1..100] of record x,y:integer end; procedure reuniune(m,n:byte; var a,b,c:multime; var card:byte); procedure intersectie(m,n:byte; var a,b,c:multime; var card:byte); procedure diferenta(m,n:byte; var a,b,c:multime; var card:byte); procedure produs_cartezian(m,n:byte; var a,b:multime; var c:produs); implementation procedure sortare(n:byte; var v:multime); var i:byte; aux:integer;vb:boolean; begin repeat vb:=false; for i:=1 to n-1 do if v[i]>v[i+1] then begin aux:=v[i]; v[i]:=v[i+1]; v[i+1]:=aux; vb:=true end until not vb
34
end; procedure compactare(var n:byte; var v:multime); var i,j,k:byte; begin sortare(n,v); k:=0; i:=1; while i<=n-k do if v[i]=v[i+1] then begin k:=k+1; for j:=i to n-k+1 do v[j]:=v[j+1] end else inc(i); n:=n-k end; procedure reuniune; const hv=maxint; var i,j,k,l:byte; begin k:=0; i:=1; j:=1; while (a[i]<>hv) or (b[j]<>hv) do if a[i]m then a[i]:=hv end else if a[i]>b[j] then begin inc(k); c[k]:=b[j]; inc(j); if j>n then b[j]:=hv end else begin inc(i); if i>m then a[i]:=hv end; card:=k end; procedure intersectie; var i,j,k:byte; begin k:=0; i:=1; j:=1; while (i<=m) and (j<=n) do if a[i]=b[j] then begin inc(k); c[k]:=a[i]; i:=i+1 end else if a[i]>b[j] then inc(j) else inc(i); card:=k end;
35
procedure diferenta; var i,j,k:byte; begin k:=0; for i:=1 to m do begin j:=1; while (a[i]<>b[j]) and (j<=n) do inc(j); if j>n then begin inc(k); c[k]:=a[i] end end; card:=k end; procedure produs_cartezian; var i,j,k:byte; begin k:=0; for i:=1 to m do for j:=1 to n do begin inc(k); c[k].x:=a[i]; c[k].y:=b[j] end end; end.
Exerciţiul 2 Să se proiecteze o unitate Pascal care să conţină subprograme pentru calcularea următorilor indicatori statistici: media aritmetică ponderată, dispersia şi abaterea medie pătratică pentru un şir de observaţii statistice. Soluţie: Pentru rezolvarea problemelor statistice trebuie avute în vedere, pe lângă observaţiile propriu-zise, şi frecvenţele de apariţie a acestora în cadrul şirului iniţial. În cadrul unităţii au fost dezvoltate două subprograme frecvente_1 şi frecvente_2, care reprezintă variante ale aceleiaşi probleme. Prima variantă determină vectorul valorilor caracteristicii observate (unice), precum şi vectorul de frecvenţe, prin parcurgerea secvenţială a şirului iniţial de observaţii statistice. Pentru fiecare observaţie iniţială se verifică existenţa în vectorul de valori unice: dacă există, atunci se incrementează frecvenţa corespunzătoare valorii respective, în caz contrar observaţia are o valoare nouă şi se adaugă şirului de valori unice. A doua variantă presupune sortarea şirului iniţial de observaţii statistice şi obţinerea vectorului valorilor caracteristicii observate (unice) şi a vectorului de frecvenţe folosind algoritmul controlului după caracteristică . Formulele utilizate pentru determinarea indicatorilor statistici sunt: n
∑ x Media:
x =
i
⋅ f i
i =1
;
n
∑ f i
i =1
36
n
∑ ( x
Dispersia:
σ
2
=
− x ) ⋅ f i 2
i
i =1
;
n
∑ f i
i =1
Abaterea medie pătratică: σ =
2 σ
.
Unitatea Pascal:
unit statist; interface type vector=array[1..50] of real; vector1=array[1..50] of byte; procedure frecvente_1(n:byte; var x,y:vector; var f:vector1; var k:byte); procedure frecvente_2(n:byte; var x,y:vector; var f:vector1; var k:byte); function media(n:byte; var x,y:vector; var f:vector1):real; function dispersia(n:byte; var x,y:vector; var f:vector1):real; function abaterea_medie_patratica(n:byte; var x,y:vector; var f:vector1):real; implementation procedure sortare(n:byte; var v:vector); var i:byte; aux:real; vb:boolean; begin repeat vb:=false; for i:=1 to n-1 do if v[i]>v[i+1] then begin aux:=v[i]; v[i]:=v[i+1]; v[i+1]:=aux; vb:=true end until not vb end; procedure frecvente_1; var i,j:byte; begin y[1]:=x[1]; f[1]:=1; k:=1; for i:=2 to n do begin j:=1; while (x[i]<>y[j]) and (j<=k) do inc(j); if j<=k then inc(f[j]) else begin inc(k);
37
end end;
y[k]:=x[i]; f[k]:=1 end
procedure frecvente_2; var i:byte; begin sortare(n,x); k:=0; i:=1; while i<=n do begin k:=k+1; y[k]:=x[i]; f[k]:=0; while (x[i]=y[k]) and (i<=n) do begin inc(f[k]); inc(i) end end end; function media; var s:real; dim,i:byte; begin frecvente_1(n,x,y,f,dim); if dim=n then begin s:=0; for i:=1 to n do s:=s+x[i]; media:=s/n end else begin s:=0; for i:=1 to dim do s:=s+y[i]*f[i]; media:=s/n end end; function dispersia; var m:real; dim,i:byte; s:real; begin m:=media(n,x,y,f); frecvente_2(n,x,y,f,dim); s:=0; for i:=1 to dim do s:=s+sqr(y[i]-m)*f[i]; dispersia:=s/n
38
end; function abaterea_medie_patratica; begin abaterea_medie_patratica:=sqrt(dispersia(n,x,y,f)) end; end.
Exerciţiul 3 Să se realizeze sortarea unui vector prin tehnica quicksort . Soluţie: Fie secvenţa (x(p),x(p+1),...,x(u)), unde p ia valoarea iniţială 1, iar u este dimensiunea vectorului. Se poziţionează x(p) astfel încât toate elementele din faţa lui să fie mai mici, iar toate de după el să fie mai mari, prin interschimbări repetate. Fie această poziţie i. Procedeul se reia pentru secvenţele (x(p),...x(i-1)), respectiv (x(i+1),...,x(u)). Poziţionarea lui x(p) se realizează astfel: 1. Se compară x(p) cu x(u), x(u-1),... până la primul u1, cu x(u1)x(u1); x(u1) şi x(p2) se interschimbă. 3. Pentru p=p2 şi u=u1 se repetă cei doi paşi până când p u. program quick_sort; uses crt; var x:array[1..100] of integer; n,i:byte; procedure poz(p,u:byte; var k:byte); var i,j:byte; l,di,dj:shortint; {di, dj sunt pasii de incrementare pentru i si j, indicand sensul parcurgerii} v:integer; begin i:=p;j:=u;di:=0;dj:=-1; while ix[j] then begin v:=x[i]; x[i]:=x[j]; x[j]:=v; l:=di;di:=-dj;dj:=-l; i:=i+di;j:=j+dj end else begin i:=i+di;j:=j+dj end; k:=i
39
end; procedure quick(p,u:byte); var i:byte; begin if p>=u then else begin poz(p,u,i); quick(p,i-1); quick(i+1,u) end end; begin {program principal} clrscr; write('Dimensiunea vectorului:'); readln(n); write('Elementele vectorului:'); for i:=1 to n do begin write('x[', i , ']= '); readln(x[i]) end; quick(1,n); for i:=1 to n do write(x[i],' ') end. Exerciţiul 4 Să se realizeze sortarea unui vector prin tehnica de interclasare. Soluţie: Paşii algoritmului sunt: 1. Se împarte vectorul în două secvenţe astfel: S1= (v1, v2, ..., v[n/2]), S2= (v[n/2]+1, ..., v[n]); 2. Se apelează recursiv procedura de sortare pentru S1 şi S2; 3. Se interclasează S1 şi S2 obţinându-se vectorul sortat.
program inter_sort; uses crt; var n,i:word; v:array[1..1000] of real; par:array[1..1000] of real; procedure interc(l,m,r:word); var i,j,k:word; begin if l
40
begin
end;
if v[i]
if i<=m then for j:=i to m do begin par[k]:=v[j]; k:=k+1 end else for i:=j to r do begin par[k]:=v[i]; k:=k+1 end end; for i:=0 to r-l do v[l+i]:=par[i+1]
end; procedure inters(l,r:word); var i:word; begin if l
41
end.
for i:=1 to n do write(v[i],' ') Exerciţiul 5
Să se determine coincidenţele produse în cadrul modelului unei linii telefonice, pe un interval de timp prestabilit, dându-se parametrii repartiţiilor exponenţiale (λ şi µ ) care caracterizează apelurile, precum şi duratele convorbirilor.
program apeluri; uses crt; type sir=array[1..100] of real; var A,D:sir; P:array[1..100] of integer; T,lambda,miu,suma:real; i,j,k,numar:integer; indic:boolean; procedure expon(medie:real;var x:real); begin x:=-ln(random)/medie end; begin clrscr; randomize; suma:=0; readln(lambda); readln(miu); readln(T); i:=0; repeat i:=i+1; expon(lambda,A[i]); expon(miu,D[i]); suma:=suma+A[i] until suma>T; numar:=i; k:=0; for i:=1 to numar do begin indic:=true; for j:=1 to numar do if((abs(A[i]-D[j])<0.11) and indic) then begin k:=k+1; P[k]:=i; indic:=false end end;
42