Documente Academic
Documente Profesional
Documente Cultură
Informatic
CUPRINS:
Introducere. 2
Ce anse am s devin un bun programator? 3
Legile succesului durabil (Ghidul studentului ndrtnic). 6
Probleme de judecat. 8
Probleme de perspicacitate. 8
Probleme cu chibrituri. 9
Probleme de logic i judecat. 10
Probleme de logic i judecat cu tent informatic. 12
Noiuni fundamentale de programare. 15
1. Cele trei etape ale rezolvrii unei probleme cu ajutorul calculatorului
15
2. Cum se stabilete corectitudinea i eficiena soluionrii? 15
3. Noiunile fundamentale ale programrii: algoritm, limbaje de descriere
a algoritmilor, program, limbaje de programare. 16
3.1. Algoritmul. 16
3.2. Descrierea algoritmilor. 17
3.3 Programul. 18
4. Secretul nvrii rapide a programrii. 19
Noiuni primare de programare n Pascal i C. 20
Exemple de probleme rezolvate. 21
Metoda practic de nvare ce garanteaz rezultate imediate. 26
Probleme selecionate Enunuri. 26
Probleme propuse spre rezolvare (probleme de antrenament). 26
Probleme de examen. 28
Probleme dificile. 30
Probleme nesoluionate nc. 32
Probleme insolvabile algoritmic. 35
Noiuni aprofundate de programare. 37
Metode i strategii de proiectare a algoritmilor (alias tehnici de
programare) 37
BackTracking. 39
Greedy. 42
Programarea dinamic. 42
Branch & Bound. 43
Recursivitatea. 44
5. Examenele grele sunt cele care i pot forma un caracter puternic. Ceea
ce este important n examen, ca i n situaiile de via, este ncrederea n
reuit i stpnirea de sine chiar dac n-ai nvat toat materia. Dac ai
nvat destul ca s te simi stpn pe tine atunci ai trecut examenul! Chiar
acesta a fost rostul lui, ce dac i-a dat not mic! Crezi c, dup ce vei trece
examenul, peste zece ani i vei mai aminti cu ce not?
6. Cei cu un caracter slab i vicios se vor da la un moment dat n vileag.
Cei care copiaz nu-i dau seama c ei i infecteaz caracterul. i nici ct de
grave sunt consecinele infectrii cu microbul ctigului imediat obinut prin
furt. Oare se vor mai putea debarasa vreodat de acest viciu tentant? Dar de
cunoscutele efecte secundare: sentimentul de nesiguran fr o fiuic n
buzunar, atracia irezistibil pentru aruncarea privirii mprejur, prerea de
ru c Ce prost sunt, puteam s copiez tot!, etc. Cnd vor mai scpa? Cei care
se obinuiesc s copieze, att ct vor tri, vor fi jumtate om-jumtate fiuic.
Ca n vechile bancuri cu miliieni.
7. Oricine este acum apt s nvee i s-i nsueasc pentru ntreaga sa
via Legea efortului. Pe profesori i impresioneaz cel mai tare efortul depus il vor aprecia cu note maxime. Ei supra-noteaz pe cei care vor, sunt bine
intenionai, dar nc nu pot. Profesorii cunosc adevrul exprimat n Legea
omului de geniu (legea lui Einstein): Geniul este compus 99% din transpiraie
i 1% din inspiraie. Profesorii adevrai se strduiesc s noteze mai ales
calitatea uman i profesional a studentului. Reinei: dac studentul a fost
prietenos, activ i deschis n timpul anului colar i a depus un efort constant
pentru a se perfeciona, fapt ce nu a scpat ochiului atent al profesorului,
examenul devine n final pentru el o formalitate.
Multe vorbe i preri pot fi auzite pe aceast tem n familie, n pauze la
coal sau la barul preferat. Ct sunt ele de adevrate? S-ar putea da oare o
definiie precis pentru succesul n via?
Noi nu cunoatem o astfel de definiie, tim doar c exist o multitudine
de preri i opinii, unele profund contradictorii. Este ns de bun sim s
credem c se poate numi de succes acea via care este plin de satisfacii,
bucurii i visuri mplinite. Acea via care s-i merite din plin exclamaia:
Asta da, via!?
Regula de aur a succesului durabil este: nva s-i construieti singur
viaa. i apoi, dac ai nvat, apuc-te fr ntrziere s-i faci viaa fericit.
Studenia, prin entuziasmul, optimismul i idealismul ei, este o perioad
optim pentru a nva cum s-i faci o via de succes! Atenie, muli i-au dat
seama prea trziu c studenia a fost pentru ei n multe privine ultimul tren.
Probleme de judecat.
Oferim n cele ce urmeaz o selecie de probleme ce nu necesit
cunotine de matematic avansate (doar nivelul gimnazial) dar care pun la
ncercare capacitatea de judecat, inspiraia i creativitatea gndirii. Rezolvarea
acestor probleme constituie un bun antrenament pentru creterea capacitii
de gndire creativ precum i a fluiditii gndirii. Credem c nu degeaba
aceste dou trsturi sunt considerate cele mai importante semne ale tinereii
minii.
10. (!) Cine mut ultimul ctig. Doi juctori dispun de o mas de joc de
form circular sau ptrat i de un numr mare de monezi identice. Ei mut
plasnd pe masa de joc n spaiul neocupat, fr suprapunere, cte o moned
alternativ pn cnd unul dintre juctori, care pierde n acest caz, nu mai
poate plasa nicieri o moned. S se arate c primul juctor are o strategie
sigur de ctig.
11. (!) Iepurele i robotul-vntor. ntr-o incint nchis (un gen de aren)
se afl un iepura i un robot-vntor nzestrat cu cleti, mijloc de deplasare,
calculator de proces i ochi electronici. tiind c viteza de deplasare a
robotului-vntor este constant i de zeci de ori mai mare dect a iepuraului,
ce anse mai are iepuraul de a scpa?
12. Cntarul defect. Avnd la dispoziie un cntar gradat defect care
greete constant cu aceeai valoare (cantitate necunoscut de grame), putem
s cntrim ceva determinndu-l corect greutatea?
13. Jocul dubleilor (inventat de Carroll Lewis). tiind c trecerea de la
un cuvnt cu sens la altul cu sens este permis doar prin modificarea unei
singure litere odat (de exemplu: UNU UNI ANI ARI GRI GOI DOI) se
cere: Dovedii c IARBA este VERDE i c MAIMUA a condus la OMENIRE,
facei din UNU DOI, schimbai ROZ-ul n ALB, punei ROUGE pe OBRAZ i
facei s fie VARA FRIG.
14. mpturirea celor 8 ptrate. mpturii iniial n opt o foaie
dreptunghiular dup care desfacei-o i nsemnai fiecare din cele opt zone
dreptunghiulare obinute (marcate de pliurile de ndoire) cu o cifr de la 1 la 8.
Putei mpturi foaia astfel obinut reducnd-o de opt ori (la un singur
dreptunghi sau ptrat) astfel nct trecnd cu un ac prin cele opt pliuri
suprapuse acesta s le perforeze exact n ordinea 1, 2, 3 8? ncercai aceste
dou configuraii:
15. Problem pentru cei puternici. ncercai s mpturii de 8 ori, pur i
simplu, o coal de hrtie (de fiecare dat linia de ndoire este n cruce peste
cea dinainte). Este posibil? (!) Determinai ce dimensiuni ar trebui s aib foaia
la nceput pentru a putea fi mpturit de 8 ori.
16. Este posibil ca un cal s treac prin toate cele 64 de ptrele ale
unei table de ah, ncepnd dintr-un col i terminnd n colul diagonal opus?
17. ntr-un atelier exist 10 ldie ce conin fiecare piese cu greutatea de
100 grame, cu excepia uneia din ldie ce conine piese avnd grutatea de 90
grame. Putei preciza care este ldia cu pricina, folosind un cntar doar pentru
o singur dat?
Probleme cu chibrituri
1. (!) Eliminnd un singur b de chibrit ceea ce rmne n faa ochilor
este un elipsoid!
2. (!) 9 bee. S se aeze 9 bee de chibrit astfel nct ele s se ntlnesc
la vrf tot cte trei n ase vrfuri distincte.
3. De la 4 la 3. n figura ce conine 4 ptrate, mutnd 4 bee s se obin
o figur ce conine doar 3 ptrate.
4. 6 = 2? Mutnd doar un singur b de chibrit s se restabileasc
egalitatea:
CCa
13. Bronx contra Brooklyn. Un tnr, ce locuiete n Manhattan n
imediata apropiere a unei staii de metrou, are dou prietene, una n Brooklyn
i cealalt n Bronx. Pentru a o vizita pe cea din Brooklyn el ia metroul ce merge
spre partea de jos a oraului, n timp ce, pentru a o vizita pe cea din Bronx, el
ia din acelai loc metroul care merge n direcie opus. Metrourile spre
Brooklyn i spre Bronx intr n staie cu aceei frecven: din 10 n 10 minute
fiecare. Dar, dei el coboar n staia de metrou n fiecare smbt la
ntmplare i ia primul metrou care vine (nedorind s favorizeze pe niciuna
din prietenele sale), el a constatat c, n medie, el merge n Brooklyn de 9 ori
din 10. Putei gsi o explicaie logic a fenomenul?
14. (!) Problema celor 12 bile. n faa noastr se afl 12 bile identice ca
form, vopsite la fel, dar una este cu siguran fals, ea fiind fie mai grea, fie
mai uoar, fiind fcut dintr-un alt material. Avem la dispoziie o balan i se
cere s determinm doar prin 3 cntriri care din cele 12 bile este fals
preciznd i cum este ea: mai grea sau mai uoar. (!) Mai mult, putei
determina care este numrul maxim de bile din care prin 4 cntriri cu balana
se poate afla exact bila fals i cum este ea?
15. (!) Problema celor 2 perechi de mnui. Aflat ntr-o situaie ce implic
intervenia de urgen, un medic chirurg constat c are la dispoziie doar 2
perechi de mnui sterile dei el trebuie s intervin rapid i s opereze
succesiv 3 bolnavi. Este posibil ca cele trei operaii de urgen s se desfoare
n condiii de protecie normale cu numai cele 2 perechi de mnui? (Sngele
fiecruia din cei 3 pacieni, precum i mna doctorului nu trebuie s conduc
la un contact infecios.)
16. (!) Problema frnghiei prea scurte. O persoan ce are asupra ei doar
un briceag i o frnghie lung de 30 metri se afl pe marginea unei stnci,
privind n jos la peretele vertical de 40 metri aflat sub ea. Frnghia poate fi
legat doar n vrf sau la jumtatea peretelui (la o nlime de 20 metri de sol)
unde se afl o mic platform de sprijin. Cum este posibil ca persoana aflat n
aceast situaie s ajung teafr jos cobornd numai pe frnghie, fr a fi
nevoit s sar deloc punndu-se astfel n pericol?
17. Problema lumnrilor neomogene. Avem la dispoziie chibrite i dou
lumnri care pot arde exact 60 minute fiecare ns, ele fiind neomogene, nu
vor arde cu o vitez constant. Cum putem msura precis o durat de 45
minute?
18. (!) O jumtate de litru. Avem n faa noastr un vas cilindric cu
capacitatea de 1 litru, plin ochi cu ap. Se cere s msurm cu ajutorul lui
litru de ap, fr a ne ajuta de nimic altceva dect de minile noastre.
19. (!) S vezi i s nu crezi. Privii urmtoarele dou figuri: prin
reaezarea decupajelor interioare ale primeia se obine din nou aceeai figur
dar avnd un ptrel lips! Cum explicai minunea?
Probleme de logic i judecat cu tent informatic
1. (!) Decriptarea scrierii ncifrate. Se dau urmtoarele numere mpreun
cu denumirile lor cifrate: nabivogedu nagevogedu nabivobinaduvogedu
nabivonagevogedunaduvogedu nabivogenagevogenaduvogedu
nabivonabivobinagevogedunagevogenaduvogedu nabivodunanabivobiduvogedu
nabivonabivonabivogedunagevogenaduvogedunanabivobiduvogedu
nabivonagevogedunagevogenanabivobiduvogedu
nabivonaduvogedunagevodunanabivobiduvogedu
nabivonabivobinagevogenaduvogedunagevodunanabivobiduvogedu
Care este regula de ncifrare? Ce numere reprezint urmtoarele coduri
cifrate: nagevonagevogedunanabivobiduvogedu;
nagevonaduvogedunanabivobiduvogedu; naduvogenanabivobiduvogedu;
nanabivogeduvogedu;
nabivonabivonaduvogedunagevonagevogedunanabivobiduvogedu;
nanagevobiduvogedu?
ncifrai numerele 256 i 1024 prin acest metod.
2. (!) Altfel de codificare binar a numerelor. Descoperii metoda de
codificare binar a numerelor folosit n continuare:
Putei spune ce numere sunt codificate prin 100, 101, 1000, 1111, 10000
i 11111? Putei codifica numerele 70, 80, 90, 100, 120, 150 i 1000?
3. (!) Problema dialogului perplex. Exist dou numere m i n din
intervalul [2.99] i dou persoane P i S astfel nct persoana P tie produsul
lor, iar S tie suma lor. tiind c ntre P i S a avut loc urmtorul dialog:
Nu tiu numerele spune P.
tiam ca nu tii rspunde S, nici eu nu tiu.
Acuma tiu! zice P strlucind de bucurie.
Acum tiu i eu. optete satisfcut S.
S se determine toate perechile de numere m i n ce satisfac acest
dialog (sunt soluii ale problemei).
4. (!) mpturirea celor 8 ptrate. mpturii iniial n opt o foaie
dreptunghiular dup care desfacei-o i nsemnai fiecare ptrel obinut cu o
cifr de la 1 la 8. Proiectai un algoritm i realizai un program care, primind
configuraia (numerotarea) celor 8 ptrele, s poat decide dac se poate
mpturi foaia astfel obinut reducnd-o de opt ori (la un singur ptrat) astfel
nct trecnd cu un ac prin cele opt foi suprapuse acesta s le perforeze exact
n ordinea 1, 2, 3 8.
5. (!) Problema fetelor de la pension. Problema a aprut pe vremea cnd
fetele nvau la pension fr ca prin prezena lor bieii s le tulbure educaia.
Pedagoaga fetelor unui pension de 15 fete a hotrt ca n fiecare dup-amiaz,
la ora de plimbare, fetele s se plimbe n cinci grupuri de cte trei. Se cere s se
stabileasc o programare a plimbrilor pe durata unei sptmni (apte zile)
astfel nct fiecare fat s ajung s se plimbe numai o singur dat cu oricare
din celelalte paisprezece (oricare dou fete s nu se plimbe de dou ori
mpreun n decursul unei sptmni).
Noiuni fundamentale de programare
Programarea este disciplina informatic ce are ca scop realizarea de
programe care s constituie soluiile oferite cu ajutorul calculatorului unor
probleme concrete. Programatorii sunt acele persoane capabile s implementeze
ntr-un limbaj de programare metoda sau algoritmul propus ca soluie
respectivei probleme, ce se preteaz a fi soluionat cu ajutorul calculatorului.
de intrare, ci ofer soluie pentru o mulime foarte larg (de cele mai multe ori
infinit) de date de intrare valide. Aceasta este trstura de baz care explic
deosebita utilitate a calculatoarelor i datorit acestei trsturi suntem siguri
c investiia financiar fcut prin cumprarea unui calculator i a produsuluisoft necesar va putea fi cu siguran amortizat. Cheltuiala se face o singur
dat n timp ce programul pe calculator va putea fi executat rapid i
economicos de un numr orict de mare de ori, pe date diferite!
De exemplu, metoda (algoritmul) de rezolvare nvat la liceu a ecuaiilor
de gradul doi: ax2+bx+c=0, se aplic cu succes pentru o mulime infinit de
date de intrare: (a, b, c) A\'7b0} xAxA.
3. Finitudinea pentru fiecare intrare valid orice algoritm trebuie s
conduc n timp finit (dup un numr finit de pai) la un rezultat. Aceast
caracteristic este analog proprietii de convergen a unor metode din
matematic: trebuie s avem garania, dinainte de a aplica metoda (algoritmul),
c metoda se termin cu succes (ea converge ctre soluie).
S observm i diferena: n timp ce metoda matematic este corect
chiar dac ea converge ctre soluie doar la infinit (!), un algoritm trebuie s
ntoarc rezultatul dup un numr finit de pai. S observm deasemenea c,
acolo unde matematica nu ofer dovada, algoritmul nu va fi capabil s o ofere
nici el. De exemplu, nu este greu de scris un algoritm care s verifice
corectitudinea Conjecturii lui Goldbach: Orice numr par se scrie ca sum de
dou numere prime, dar, dei programul rezultat poate fi lsat s ruleze pn
la valori extrem de mari, fr s apar nici un contra-exemplu, totui
conjectura nu poate fi astfel infirmat (dar nici afirmat!).
3.2. Descrierea algoritmilor
Dou dintre metodele clasice de descriere a algoritmilor sunt denumite
Schemele logice i Pseudo-Codul. Ambele metode de descriere conin doar patru
operaii (instruciuni) elementare care au fiecare un corespondent att schem
logic ct i n pseudo-cod.
n cele ce urmeaz vom nira doar varianta oferit de pseudo-cod
ntruct folosirea schemelor logice s-a redus drastic n ultimii ani. Schemele
logice mai pot fi ntlnite sub numele de diagrame de proces n anumite cri de
specialitate inginereti. Avantajul descrierii algoritmilor prin scheme logice este
dat de libertatea total de nlnuire a operaiilor (practic, sgeata care descrie
ordinea de execuie, pleac de la o operaie i poate fi trasat nspre orice alt
operaie). Este demonstrat matematic riguros c descrierea prin pseudo-cod,
dei pare mult mai restrictiv (operaiile nu pot fi nlnuite oricum, ci trebuie
executate n ordinea citirii: de sus n jos i de la stnga la dreapta), este totui
perfect echivalent. Deci, este dovedit c plusul de ordine, rigoare i simplitate
pe care l ofer descrierea prin pseudo-cod nu ngrdete prin nimic libertatea
programrii. Totui, programele scrise n limbajele de asamblare, care sunt
mult mai compacte i au dimensiunile mult reduse, nu ar putea fi descrise
altfel dect prin scheme logice.
1. Atribuirea var: =expresie;
2. Intrare/Ieire Citete var1, var2, var3,.;
Scrie var1, var2, var3,.; sau Scrie expresia1, expresia2, expresia3,.;
Begin
Writeln (x1=, (-b-sqrt (delta)/(2*a):6:2);
Writeln (x2=, (-b+sqrt (delta)/(2*a):6:2);
End else Begin
Writeln (z1= (.
B/(2*a):6:2, , .
Sqrt (-delta)/(2*a):6:2, ) );
Writeln (z2= (.
B/(2*a):6:2, , , sqrt (-delta)/(2*a):6:2, ) );
End
Readln;
END.
/versiunea C include <stdio. H> include <math. H> float a, b, c;
/coeficienii ecuaiei de gradul II float delta; void main (){printf (Introd. Coefic.
Ecuaiei a b c:); scanf (%f %f %f, &a, &b, &c); delta=b*b-4*a*c; if (delta>=0)
{printf (Sol. Reale: x1=%6.2f, x2=%6.2f, (-b+sqrt (delta)/2. /a, (-b-sqrt
(delta)/2. /a);
} else {printf (Sol. Complexe: x1= (%6.2f, %6.2f), x2= (%6.2f, %6.2f).
B/2. /a, sqrt (-delta)/2. /a. -b/2/a. -sqrt (- delta)/2. /a);
2. S se determine dac trei numere a, b, c reale pot reprezenta laturile
unui triunghi. Dac da, s se caculeze perimetrul i aria sa.
Descrierea algoritmului:
Condiia necesar pentru ca trei numere s poat fi lungimile laturilor
unui triunghi este ca cele trei numere s fie pozitive (condiie implicit) i suma
a oricror dou dintre ele s fie mai mare dect cel de-al treilea numr
Dup condiia este ndeplinit vom calcula perimetrul i aria triunghiului
folosind formula lui Heron s=sqrt (p (p-a)(p-b)(p-c) unde p= (a+b+c)/2.
Program Laturile_Unui_Triunghi; {Pascal}
Var a, b, c, s, p: real; function laturi_ok: boolean; begin laturi_ok: = (a>0)
and (b>0) and (c>0) and (a+b>c) and (a+c>b) and (b+c>a); end;
BEGIN write (introduceti laturile); readln (a, b, c);
IF laturi_ok then begin p: = (a+b+c)/2; s: =sqrt (p*(p-a)*(p-b)*(p-c); writeln
(Aria=, s:5:2); writeln (Perimetrul=, 2*p:5:2); end else writeln (Nu formeaz
triunghi); readln;
END.
/versiunea C include <stdio. H> include <math. H> float a, b, c, s, p; int
validare_laturi (float a, float b, float c){return (a>0) & (b>0) & (c>0) & (a+b>c) &
(b+c>a) & (a+c>b); void main (void){printf (Introd. Laturile a b c:); scanf (%f %f
%f, &a, &b, &c); if (validare_laturi (a, b, c){p= (a+b+c)/2; s=sqrt (p*(p-a)*(pb)*(p-c); printf (Aria=%6.2f, Perimetrul=%6.2f, s, 2*p);
3. Se citete n ntreg. S se determine suma primelor n numere naturale.
Descrierea algoritmului:
Vom oferi varianta n care suma primelor n numere naturale va fi
calculata cu una dintre instruciunile repetitive cunoscute (for, while, repeat)
fr a apela la formula matematic cunoscut S (n) =n*(n+1)/2
Program Suma_n; {Pascal}
Var n, s, i: word;
BEGIN
Writeln (Introduceti limita n=); Readln (n); s: =0;
For i: =1 to n do s: =s+i;
Writeln (s=, s);
Readln;
END.
/versiunea C include <stdio. H> int n, s; void main (void){printf (Introd.
N:); scanf (%i, &n); for (; n>0; n-) s+=n; printf (S (n) =%i, s);
4. Se citete valoarea ntreag p. S se determine daca p este numr
prim.
Descrierea algoritmului:
Un numr p este prim dac nu are nici un divizor nafar de 1 i p cu
ajutorul unei variabile contor d vom parcurge toate valorile intervalului [2. p];
acest interval este suficient pentru depistarea unui divizor, cci: d1 | p p =
d1*d2 (unde d1 < d2) d1 d1*d2 = p iar d2 d1*d2 = p
Program Nr_prim; {Pascal}
Var p, i: word; prim: boolean;
BEGIN write (p=); readln (p); prim: =true; for i: =2 to trunc (sqrt (p) do if
n mod i=0 then prim: =false; prim: =true; if prim then write (p, este nr prim)
else write (p, nu e nr prim);
END.
/versiunea C (optimizat!) include <stdio. H> include <math. H> int p, i,
prim; void main (void){printf (Introd. P:); scanf (%i, &p); for (i=3, prim=p % 2;
(i<=sqrt (p) & (prim); i+=2) prim=p % i; printf (%i %s nR. Prim, p, (prim? este:
nu este);
5. Se citete o propoziie (ir de caractere) terminat cu punct. S se
determine cte vocale i cte consoane conine propoziia.
Program Vocale;
Var sir: string [80];
Vocale, Consoane, i: integer;
BEGIN
Write (Introd. Propoziia terminata cu punct:); Realn (sir); i: =1; Vocale:
=0; Consoane: =0;
While sir [i] <>. do begin
If Upcase (sir [i]) n [A, E, I, O, U] then Inc (Vocale) else If Upcase (sir
[i]) n [A.Z] then Inc (Consoane);
Inc (i); end;
Writeln (Vocale:, Vocale, Consoane:, Consoane, Alte caractere:, iVocale-Consoane);
END.
/versiunea C include <stdio. H> include <ctype. H> int i, vocale=0,
consoane=0; char c, sir [80]; void main (void){printf (Introd. Propoziia
terminata cu punct:); gets (sir); for (i=0; sir [i]! =.; i+) switch (toupper (sir
[i]){case A: case E: case I: case O: case U: vocale+; break; default: if (isalpha
(sir [i]) consoane+; printf (Vocale: %i, Consoane: %i, Alte car.: %i, vocale,
consoane, i-vocale-consoane);
Metoda practic de nvare ce garanteaz rezultate imediate
Dac cele spuse mai sus cu privire la secretul nvrii rapide a
programrii, acum nu ne mai rmne dect s ncepem s aplicm practic
ideile prezentate. Pentru aceasta, avem la dispoziie urmtoarea metod care
garanteaz cu siguran rezultate. Iat-o, pe pai:
1. Se citete i se nelege ct mai bine exemplul de problem rezolvat
(se poate ncepe chiar cu primul exemplu de mai sus)
2. Se acoper (se ascunde) soluia i se ncearc reproducerea ei din
memorie (reinventarea soluiei) pe calculator
3. Numai n cazuri excepionale se poate apela (se poate trage cu ochiul)
la soluie
Oricare dintre noi poate recunoate aici metoda pe care o aplic copiii din
primele clase primare: metoda trasului cu ochiul la rezultatul aflat la spatele
manualului sau al culegerii de probleme. Din moment ce metoda este verificat
i garantat (am folosit-o i noi cndva), de ce ne-ar fi ruine s-o aplicm acum
din nou?
Iat n continuare o list de probleme de antrenament care au majoritea
rezolvarea ntr-unul din capitolele urmtoare. Este numai bine pentru a ncepe
s aplicm metoda oferit chiar acum!
Probleme selecionate Enunuri
Probleme propuse spre rezolvare (probleme de antrenament)
1. Se citesc a, b, c trei variabile reale.
S se afieze maximul i minimul celor trei numere.
S se afieze cele trei numere n ordine cresctoare.
S se determine dac cele trei numere pot reprezenta laturile unui
triunghi. Dac da, s se determine dac triunghiul respectiv este isoscel,
echilateral sau oarecare.
S se determine dac cele trei numere pot reprezenta laturile unui
triunghi. Dac da, s se determine mrimile unghiurilor sale i dac este
ascuit-unghic sau obtuz-unghic.
S se afieze media aritmetic, geometric i hiperbolic a celor trei
valori.
2. Se citete n o valoare ntreag pozitiv.
S se determine dac n este divizibil cu 3 dar nu este divizibil cu 11.
S se determine dac n este ptrat sau cub perfect.
S se afieze primele n ptrate perfecte.
S se determine numrul cuburilor perfecte mai mici dect n.
S se gseasc primul numr prim mai mare dect n.
S se afieze primele n numere prime: 2, 3, 5, 7 pn.
S se determine toate numerele de 4 cifre divizibile cu n.
S se determine suma cifrelor lui n.
S se afieze rsturnatul lui n. (Ex: n=1993 => n_rsturnat =3991).
S se afieze urmtorul triunghi de numere:
12 3. N
64, 125,. Apoi cele de grad 4, 5,. Vom constata c singurele dou numere
ncercuite alturate sunt 8 i 9! Adic puterile obinute, cu ct sunt mai mari,
cu att au tendina s se mprtie i s se distaneze unele de altele tot mai
tare. n mod misterios, ele nu-i suport vecintatea unele cu altele!
2. Conjectura cutiei raionale. Nu se cunoate existena unei cutii
paralelipipedice avnd lungimile celor trei laturi, ale celor trei diagonale ale
feelor i a diagonalei principale ntregi.
Observaie: ntr-o exprimare matematic riguroas, nu se cunoate s
existe trei ntregi a, b, c astfel nct a2+b2, b2+c2, c2+a2i a2+b2+c2s fie toate
patru ptrate perfecte.
Comentariu: n multe subdomenii ale construciilor, de exemplu s ne
gndim la stlpii de nalt tensiune ridicai pe vrfuri nalte de munte i
asamblai n ntregime la faa locului numai din bare mbinate cu uruburi
(fr sudur), este de mare interes ca dintr-un numr ct mai mic de
subansamble simple (un fel de crmizi) s se asambleze obiecte mari cu ct
mai multe configuraii. Evident, dimensiunile obiectelor rezultate vor avea
mrimea ca o combinaie ntreag ale dimensiunilor subansamblelor iniiale.
Dup cum rezult ns din conjectur, se pare c este imposibil s se
construiasc scheletul ntrit (pe diagonale) al unei cutii paralelipipedice din
bare de lungimi tipizate. Cel puin una din diagonale necesit ajustarea
lungimii unei bare!
3. Problema umplerii ptratului unitate. ntrebare: este posibil ca
mulimea dreptunghiurilor de forma 1/k x 1/(k+1), pentru fiecare k ntreg
pozitiv, s umple n ntregime i fr suprapuneri ptratul unitate, de latur
1x1?
Observaie: este evident c suma infinit a ariilor dreptunghiurilor este
egal cu aria ptratului unitate. Avem Sk>01/(k (k+1) =Sk>0(1/k-l/(k+1) =1.
Comentariu: aparent, descoperirea dezvoltrilor n serie pare s fi plecat
de la unele evidente propieti geometrice, uor de sesizat chiar din desene
simple n care valorilor numerice li se asociaz segmente de lungimi
corespunztoare. Iat ns o surpriz n aceast situaie: suma seriei numerice
este evident analitic ns reprezentarea geometric a fenomenului este
imposibil!
4. Conjectura fraciilor egiptene (atribuit lui Erds i Graham). Orice
fracie de forma 4/n se descompune ca sum de trei fracii egiptene (de forma
1/x).
Observaie: ntr-o exprimare matematic riguroas, pentru orice n natural
exist trei valori naturale, nu neaprat distincte, x, y i z astfel nct
4/n=1/x+1/y+1/z.
Comentariu: este nc un mister motivul pentru care egiptenii preferau
descompunerea faciilor numai ca sum de fracii egiptene. Descoperiser ei
aceast descompunere minimal a fraciilor de forma 4/n? Dar mai ales, ce
procese fizice reale erau astfel mai bine modelate? nclinm s credem c exist
o legtur ntre fenomenele fizice ondulatorii, transformata Fourier i fraciile
egiptene!
de aceste probleme chiar i din greeal?!) i care este pcat s fie tratat ntrun mod superficial.
1. Problema Stopului. Nu exist un algoritm universal valabil prin care s
se poat decide dac execuia oricrui algoritm se oprete vreodat sau nu.
Comentariu: acesta este cel dinti i cel mai celebru exemplu de
problem insolvabil. Demonstraia riguroas a acestui fapt a fost dat pentru
prima dat n 1936 de inventatorul calculatorului actual matematicianul englez
Alan Mathison Turing. Odat existnd aceast demonstraie, multe din
urmtoarele probleme insolvabile algoritmic s-au redus la aceasta. Implicaiile
practice, teoretice i filosofice ale problemei Stopului sunt foarte importante
att pentru informatic ct i pentru matematic. Astfel, dou consecine
strategice ale problemei Stopului sunt: 1. Nu poate exista un calculator orict
de puternic cu ajutorul cruia s se poat decide asupra comportamentului
viitor al oricrui alt calculator de pe glob; 2. Nu poate s existe n matematic o
metod general de demonstrare inductiv-logic a propoziiilor matematice (se
nchide n acest fel o mai veche cutare a matematicienilor i logicienilor
cunoscut sub numele de Entscheidungs Problem sau Problema deciziei).
2. Problema ecuaiilor diofantice. Nu exist o metod general (un
algoritm) de aflare a soluiilor ntregi ale unui sistem de ecuaii diofantice.
Comentariu: sistemele de ecuaii diofantice sunt sistemele de ecuaii
algebrice de mai multe variabile cu coeficieni ntregi i crora li se caut soluii
ntregi. De exemplu, a fost nevoie de ajutorul calculatorului pentru a se
descoperi cea mai mic soluie a ecuaiei diofantice p4+q4+r4=s4 i care este
cvadrupletul p=95600, q=217519, r=414560, s=422461 (infirmndu-se n acest
fel conjectura lui Leonard Euler care n 1796 a presupus c aceast ecuaie
diofantic nu are soluii ntregi). Aceast problem ce cere o metod general de
rezolvare a ecuaiilor diofantice este cunoscut sub denumirea de Problema a
10-a a lui Hilbert.
3. Problema acoperirii planului (Problema pavajului sau Problema croirii).
Fiind dat o mulime de forme poligonale, nu exist o metod general (un
algoritm) care s decid dac cu aceste forme este posibil acoperirea complet
a planului (fr suprapuneri i goluri).
Comentariu: n practic este mult mai important problema croirii care
cere s se decupeze fr pierderi un set ct mai mare de forme date (croiuri)
dintr-o bucat iniial de material orict de mare. Este deasemenea demonstrat
c problema rmne insolvabil algoritmic chiar i atunci cnd formele
poligonale sunt reduse la poliomine (un fel de mozaicuri) care se formeaz
doar pe o reea rectangular caroiat. Iat cteva exemple de mulimi formate
dintr-o singur poliomin i, alturat, rspunsul la ntrebarea dac cu ele se
poate acoperi planul sau nu:
DA NU DA
4. Problema irurilor lui Post. Se dau dou mulimi egale de iruri finite
de simboluri ce sunt mperecheate astfel: un ir dintr-o mulime cu irul
corespunztor din a doua mulime. Nu exist un algoritm general prin care s
se decid dac exist o ordine de concatenare a irurilor (simultan din cele
dou mulimi) astfel nct cele dou iruri lungi pereche rezultate s fie
identice.
Comentariu: de exemplu, fie A= {101, 010, 00} i B= {010, 10, 001} cele
dou mulimi de iruri de simboluri (pentru uurin au fost alese simbolurile
binare 1 i 0). Perechile corespunztoare de iruri sunt 1. (101,010), 2. (010,10)
i 3. (00,001). Observm c irurile pereche pot avea lungimi diferite (ca n
perechile 2 i 3). n continuare, pentru a vedea cum se procedeaz, cele dou
iruri pereche rezultante prin concatenare le vom scrie unul deasupra celuilalt
sesiznd cum avanseaz procesul de egalizare a lor. Punctele sunt intercalate
doar pentru a evidenia perechile, ele nu contribuie la egalitate, iar comentariile
ne aparin:
Concatenarea poate ncepe doar cu
Obligatoriu urmeaz perechea l-a perechea a 3-a, 00 de sus 001 de
jos singura care ncepe cu 1 sus.
Dac am continua cu perechea
. Nu s-ar obine rezultatul final a 3-a.
001.010.10 oferit de perechea 2-a!
5. Problema cuvintelor egale. Se d un anumit numr de egaliti ntre
cuvinte. Bazndu-ne pe aceste egaliti se pot obine unele noi substituind
apariiile cuvintelor dintr-o parte a egalului cu cele din cealalt parte. Nu exist
un algoritm general de a decide dac un cuvnt oarecare A poate fi egal cu un
altul B.
Comentariu: de exemplu, fie urmtoarele cinci egaliti (citii-le n limba
englez) EAT=AT, AE=A, LATER=LOW, PAN=PILLOW i CARP=ME. Este
CATERPILLAR egal cu MAN? Iat irul egalitilor iterate care ne poate oferi
rspunsul: CATERPILLAR = CARPILLAR =CARPILLATER =CARPILLOW=
CARPAN= MEAN= MEATEN= MATEN= MAN.
Dar de la CARPET putem ajunge la MEAT? ntruct se vede c numrul
total de A-uri plus W-uri i M-uri nu se poate modifica prin nici o substituie i
ntruct CARPET are un A (adic numrul asociat este 1) iar MEAT are un A i
un M (deci 2), rezult c aceast egalitate nu este permis.
Mai mult, se tie c exist liste particulare de cuvinte pentru care nu
poate exista un algoritm ce decide dac dou cuvinte sunt egale sau nu. Iat o
astfel de list de apte egaliti: AH=HA, OH=HO, AT=TA, OT=TO, TAI=IT,
HOI=H i THAT=ITHT.
Numrul problemelor cunoscute ca fiind insolvabile algoritmic este destul
de mare. Cele mai multe probleme provin din matematic, subdomeniul
matematicii care studiaz aceste probleme se numete Matematica nerecursiv.
De aceea ele pot fi ntlnite mai ales sub numele de probleme nedecidabile sau
probleme nerecursive, n enunul lor cuvntul algoritm fiind nlocuit mai ales
cu cuvintele metod general.
Studierea acestui domeniu a creat condiii pentru apariia de noi direcii
de cercetare prin care se ncearc explicarea raionamentelor matematice ba
chiar se ncearc descoperirea limitelor raiunii umane n general. Unii oameni
de tiin contemporani, cum este celebrul matematician-fizician englez Roger
Penrose, depun eforturi mari pentru a oferi o demonstraie matematic
Euclid de determinare a celui mai mare divizor comun a dou numere prin
mpriri ntregi repetate. Argumentele elevilor de forma: Este corect pentru c
aa ne-a nvat doamna profesoar! sau Este corect pentru c aa face toat
lumea! sunt normale att timp ct nu li se ofer o argumentaie matematic
riguroas.
Ideea central a etapei a doua proiectarea uni algoritm de soluionare
eficient poate fi formulat astfel: din studiul proprietilor i limitelor modelului
matematic abstract asociat problemei se deduc limitele inferioare ale
complexitii minimale (efortului minimal obligatoriu) inerente oricrui
algoritm ce va soluiona problema n cauz. Complexitatea intern a modelului
abstract i complexitatea soluiei abstracte se va reflecta imediat asupra
complexitii reale a algoritmului, adic asupra eficienei, de soluionare a
problemei. Acest fapt permite prognosticarea nc din aceast faz faza de
proiectare a algoritmului de soluionare a eficienei practice, msurabil ca
durat de execuie, a programului.
Aceast coresponden exact ntre complexitatea modelului abstract i
complexitatea algoritmului de soluionare ofer cheia unor demonstraii
riguroase a imposibilitii existenei soluiei prin metode algoritmice pentru o
list ntreag de probleme (cum ar fi de exemplu Problema a 10-a a lui Hilbert,
formulat nc din 1900).
Detailnd cele prezentate deja, vom construi n continuare cadrul teoretic
general pentru nelegerea strategiilor de proiectare a algoritmilor.
Creterea impresionant a puterii de calcul a calculatoarelor i-a obligat
pe informaticienii ultimilor treizeci de ani s nu se mai eschiveze de la
abordarea problemelor dificile cu caracter algoritmic din diverse domenii care
au intrat n atenia matematicienilor nc de la nceputul acestui secol. De
altfel, astfel de probleme cu soluii algoritmice nu constituiau neaprat o
noutate pentru matematicienii nceputului de secolul. nc de pe vremea lui
Newton matematicienii i-au pus, de exemplu, problema descoperirii unor
metode precise (adic algoritmi!) de determinare n pai de aproximare
succesiv a soluiei unei ecuaii ce nu poate fi rezolvat prin radicali. Dar
boom-ul dezvoltrii tehnicii de calcul din a doua jumtate a secolului a creat
posibilitatea abordrii unor probleme cheie pentru anumite domenii strategice
(de exemplu, controlul i dirijarea sateliilor pe orbit, probleme de planificare
sau optimizare n economie, etc.) care se reduc n fapt la soluionarea eficient
a unor probleme de optimizare matematic prin metode iterative (algoritmi).
Spre deosebire de aceste probleme a cror succes n soluionare a fost
total i cu consecinele ce se vd, exist ns o serie de probleme dificile
inspirate din realitate care se cer imperios rezolvate eficient cu ajutorul
calculatorului.
Principal caracteristic a acestora este c, datorit generalitii lor sau
datorit dificultii ascunse, n literatura de specialitate nu exist metode
iterative eficiente de rezolvare a lor i nu se tie dac ele admit astfel de soluii.
Singurul fapt ce poate fi stabilit dinainte n cazul soluionrii unor astfel de
probleme este spaiul n care soluia trebuie cutat. Ceea ce trebuie atunci
arborele parcurgerii n lime. n aceast situaie, dintr-un nod sunt vizitai toi
vecinii (nevizitai nc), iar apoi se face repet acelai lucru pentru fiecare nod
vecin, n ordinea vizitrii. Se observ cum nodul 7 este vizitat naintea nodului
6, fiind vecin cu nodul 4. (De fapt, aceasta se explic prin faptul c distana de
la 1 la 7 este mai mic cu o unitate dect distana de la 1 la 6.) Putem spune c
n cazul traversrii n lime ordinea de traversare este dat de deprtarea
nodurilor fa de nodul de start.
Iat cum arat procedura general DepthFirstsearch (DFS) de traversare
a unui graf descris n pseudo-cod n varianta recursiv:
Procedura DFS (v: nod);
Viziteaz v;
Marcheaz v; /v devine un nod vizitat/
Ct timp (exist w nemarcat nod adiacent lui v) execut DFS (w);
S nu uitm c aceast procedur poate fi privit ca scheletul pe care
se construiete orice procedur backtracking recursiv.
BackTracking.
Pentru a preciza mai exact n ce const aceast metod, vom relua pe un
exemplu concret cele spuse deja. Avem urmtoarea problem: se cere generarea
tuturor permutrilor unei mulimi de n elemente ce nu conin elementul x (dat
dinainte) pe primele dou poziii. Conform celor afirmate, este suficient s
construim modelul abstract graful (mai precis arborele) tuturor
permutrilor celor n elemente. Apoi, printr-o parcurgere exhaustiv a nodurilor
sale, prin una din metodele BFS sau DFS, s pstrm numai acele noduri ce
verific n momentul vizitrii condiia impus (lipsa lui x de pe primele dou
poziii).
Observm c aceast metod necesit folosirea n scopul memorrii
dinamice a drumului parcurs (n timpul cutrii soluiei) a mecanismului de
stiv, fapt sugerat chiar de numele ei: tracking, adic nregistrarea pistei
parcurse. Acest mecanism de stiv, care permite att memorarea pistei ct i
revenirea back-tracking-ul, este unul din mecanismele de baz ce este folosit
pe scar larg n procedurile de gestiune dinamic a datelor n memorie. n
plus, exist unele cazuri particulare de probleme n care soluia cutat se
obine n final prin vrsarea ntregului coninut al stivei i nu doar prin
nodul ultim vizitat, aflat n vrful stivei.
Exemplul cel mai potrivit de problem ce necesit o strategie de rezolvare
backtracking este Problema Labirintului: se cere s se indice, pentru o
configuraie labirintic dat, traseul ce conduce ctre ieirea din labirint. Iat
un exemplu sugestiv:
L
15
Observai cum, dup 15 pai, este necesar o revenire (backtracking)
pn la csua 6, de unde se continu pe o alt pist. Pista fals a fost
memorat n stiv, element cu element, iar revenirea se va realiza prin
eliminarea din stiv tot element cu element. Cnd n vrful stivei reapare
csua cu numrul 6, stiva ncepe din nou s creasc memornd elementele
noului drum. n final stiva conine n ntregime soluia: drumul corect ctre
ieirea din labirint.
J
n consecin, indiferent de forma particular ce o poate lua sau de
modul n care este citit n final soluia, esenialul const n faptul c
backtracking-ul este o metod de programare ce conine obligatoriu gestiune de
stiv. Lipsa instruciunilor, explicite sau transparente, de gestionare a stivei
ntr-un program (de exemplu, lipsa apelului recursiv), este un indiciu sigur de
recunoatere a faptului c acel algoritm nu folosete metoda sau strategia de
rezolvare BackTracking.
Tot o metod back-tracking este i metoda de programare cunoscut sub
numele programare recursiv. Ea este mai utilizat dect metoda clasic
BackTracking, fiind mai economicoas din punctul de vedere al minimizrii
efortului de programare. Aceast metod se reduce la construirea, n mod
transparent pentru programator, a arborelui apelurilor recursive, traversarea
acestuia prin apelarea recursiv (repetat) i efectuarea aciunilor
corespunztoare n momentul vizitrii fiecrui nod al arborelui. Apelarea
recursiv constituie motorul vehiculului de traversare i are doar rolul de a
permite traversarea arborelui. Gestionarea stivei apelurilor recursive i
revenirea back-tracking-ul rmne n sarcina mediului de programare folosit
i se efectueaz ntr-un mod mascat pentru programator. Din acest punct de
vedere, programatorului i revine sarcina scrierii corecte a instruciunii de apel
recursiv i a instruciunii ce scurt-circuiteaz bucla infinit a apelurilor
recursive. Singurele instruciuni care fac treab, n sensul rezolvrii
propriuzise a problemei respective, sunt cele cuprinse n corpul procedurii.
De exemplu, iat cum arat n limbajul de programare Pascal procedura
general de generare a permutrilor n varianta recursiv i arborele de
generare a permutrilor mulimii {1,2,3} (n=3), pe nivele:
Procedure Permut (k: byte; s: string); {k nivelul n arbore, s irul}
Var i: byte; tmp: char;
Begin
If k=n then begin {scurt-circuitarea recursivitii}
For i: =1 to n do Write (s [i]); {prin afiarea permutrii}
Write (;); {urmat de un punct-virgul} end else
For i: =k to n do begin {singurele instruciuni ce fac treab} tmp: =s [i]; s
[i]: =s [k]; s [k]: =tmp; {sunt for-ul i cele trei atribuiri}
Permut (k+1, s); {apelul recursiv ce permite parcugerea} end; {arboR. De
generare a celor n! Permutri}
End;
Nivelele arborelui (rsturnat pe orizontal)
Fiecare nivel al arborelui corespunde unei poziii n irul permutrilor.
Astfel, pe prima
2 poziie (nivelul 1) pot fi oricare din cele trei elemente: 1, 2, 3. Pe poziia
urmtoare pot
3 fi oricare din celelalte dou elemente rmase: 2, 3; 1, 3; 1, 2. Pe al
treilea nivel i ultimul
Start 2 <
1 vor fi numai elementele rmase (cte unul). Generarea permutrilor
const n construirea
\par
2 i parcurgerea arborelui permutrilor: odat ajuni cu parcurgerea la
un capt din dreapta
1 vom afia de fiecare dat drumul de la rdcin la frunza
terminal.
Observm c arborele permutrilor este identic cu arborele apelurilor
recursive i c controlul i gestiunea stivei se face automat, transparent fa de
programator. Instruciunilor de control (din background) le revine sarcina de a
pstra i de a memora, de la un apel recursiv la altul, string-ul s ce conine
permutrile. Dei aceast procedur recursiv de generare a permutrilor pare o
variant de procedur simpl din punctul de vedere al programatorului, n
realitate, ea conine ntr-un mod ascuns efortul de gestionare a stivei:
ncrcarea-descrcarea stringului s i a ntregului k. Acest efort este preluat n
ntregime de instruciunile incluse automat de mediul de programare pentru
realizarea recursivitii.
Avantajul metodei back-tracking este faptul c efortul programatorului se
reduce la doar trei sarcini:
1. construirea grafului particular de cutare a soluiilor
2. Adaptarea corespunztoare a uneia din metodele generale de
traversare-vizitare a grafului n situaia respectiv (de exemplu, prin apel
recursiv)
3. Adugarea instruciunilor ce fac treab care, fiind apelate n mod
repetat n timpul vizitrii nodurilor (grafului soluiilor posibile), rezolv gradat
problema, gsind sau construind soluia.
Aciunea de revenire ce d numele metodei, backtracking revenire pe
pista lsat, este inclus i este efectuat de subalgoritmul de traversare a
grafului soluiilor posibile. Acest subalgoritm are un caracter general i face
parte din zestrea oricrui programator. n cazul particular n care graful
soluiilor este arbore, atunci se poate aplica ntotdeauna cu succes metoda
programrii recursive care conduce la un cod-program redus i compact.
Prezentm din nou procedura general DepthFirstsearch (DFS) de
traversare a unui graf n varianta recursiv (ce construiete de fapt arborele
de traversare a grafului avnd ca rdcin nodul de pornire) pentru a pune n
eviden cele spuse.
Procedura DFS (v: nod);
Viziteaz v; {aici vor fi acele instruciuni care fac treab}
Marcheaz v; /v devine un nod vizitat/ {poate s lipseasc n anumite
implementri}
Ct timp (exist w nemarcat nod adiacent lui v) execut DFS (w); {apelul
recursiv este motorul vehiculului}
{ce permite parcurgerea grafului i gestiunea stivei de revenire}
Exist situaii n care, la unele probleme, putem ntlni soluii tipbacktracking fr ns a se putea sesiza la prima vedere prezena grafului de
} void calc_coef (int i){if (i>m+n) return; else c [i] =suma_prod (i, 0);
} void citete_coef (float a [], int i){if (i>n) return; else {printf (%i:, i); scanf
(%f, &a [i]); citete_coef (a, i+1);}
} void afis_coef (float a [], int i){if (i>n) return; else {printf (%f , a [i]);
afis_coef (a, i+1);}
} void main (){printf (m (gradul polinomului P) =); scanf (%i, &m); printf
(Introd. Coef. Polinomului P:); citete_coef (a, 0); printf (n (gradul polinomului
Q) =); scanf (%i, &n); printf (Introd. Coef. Polinomului Q:); citete_coef (b, 0);
calc_coef (0); afis_coef (c, 0);
8. Se citete n, o valoarea ntreag pozitiv, s se determine suma cifrelor
lui n.
Include <stdio. H> int n; int suma (int n){if (n<10) return n; else return
n%10+suma (n/10);
} void main (){printf (n=); scanf (%i, &n); printf (suma cifrelor=%i,
suma (n);
Probleme rezolvate i exerciii de programare
Vom ncepe prin a face o observaie important: exist totdeauna un
pericol n oferirea pe tav a soluiilor la probleme. n urmtoarele
subcapitolele nu am fost deloc zgrcii i se pot gsi destule probleme
rezolvate att n Pascal ct i n C, dei pentru unele vei putea gsi rezolvarea
doar ntr-unul din limbaje. Pericolul const n faptul c, nceptorilor lenei,
lipsii de voin i nclinai ctre a copia mereu, li se ofer posibilitatea s nu-i
mai bat capul cu rezolvarea problemelor acum cnd au totul de-a gata.
Desigur, cei care ies n pierdere sunt tot ei. Ne-am asumat acest risc gndindune nu att la cei lenei ct mai ales la programatorii nceptori bine-lntenionai
crora aceste probleme, cu rezolvrile lor tipice, le poate fi de un real folos.
Putem spune c urmat astfel exemplul autorilor mediilor de programare Turbo
Pascal i Turbo C (sau Borland) care prin help-urile lor generoase au contribuit
decisiv la formarea multor generaii de programatori.
V avertizm c, n practica concret de programare, programatorul (care
nu este i analist) primete de la cel care a analizat nainte problema doar
indicaii de programare. Rareori analistul pune la dispoziia programatorului i
o descriere n pseudocod a algoritmilor ce trebuiesc implementai. Deci, nici un
programator nceptor nu trebuie s-i fac iluzia c generozitatea din acest
capitol o va mai ntlni vreodat n practica concret de programare sau c va
avea vreodat la dispoziie surse abundente de inspiraie. Este cert c n
practic lipsa inspiraiei va trebui compensat prin transpiraie.
Probleme elementare. Exerciii de programare
Oferim n continuare o mulime de probleme de programare clasice
rezolvate ntr-un mod didactic. Am adugat naintea celor dou versiuni de
soluionare n cele dou limbaje de programare, Pascal i C, cteva rnduri ce
cuprind elementele de baz ale analizei probleme.
Ne-am strduit s aezm problemele n ordinea dificultii lor, de la cele
elementare spre cele mai dificile. De aceea este recomandat ca ele s fie
parcurse n aceast ordine.
END.
/soluia n limbajul C include <stdio. H> include <math. H> float a, b, c,
ma, mg, mh; void main (void){printf (a=); scanf (%f, &a); printf (b=); scanf
(%f, &b); printf (c=); scanf (%f, &c); printf (ma=%6.3f, (a+b+c)/3.); if (a=0
|| b=0 || c=0){printf (mg=0); printf (Nu putem calcula media hiperbolica);
} else {if (a*b*c>0) then writeln (mg=%6.3f, pow (a*b*c, 1. /3.); else printf
(Nu putem calcula media geometrica, nr negative.); printf (mh=%6.3f, 3.
/(1/a+1/b+1/c);
S se determine suma primelor n numere naturale.
Analiza problemei elaborarea algoritmului:
Suma primelor n numere naturale poate fi calculata, fr a folosi formula
cunoscut, cu una dintre instruciunile repetitive cunoscute (for, while, repeat)
Indiferent de instruciunea repetitiva folosita trebuie iniializata suma cu
0 (s=0)
Folosim un contor i (1, n) care la fiecare pas se incrementeaz cu 1 i se
aduna la s
Ciclul se ncheie cnd valoarea lui i>n
Daca folosim instruciunea for, numrul pailor este cunoscut, valoarea
iniial a contorului fiind 1, iar cea finala fiind n.
Program suma; var s, i: word;
BEGIN writeln (Introduceti limita n=); readln (n); s: =0; for i: =1 to n do s:
=s+i; writeln (s=, s); readln;
END.
/soluia n limbajul C include <stdio. H> unsigned s, i; void main
(void){printf (Introducei n=); scanf (%u, &n); for (s=0, i=1; i<=n; i+) s+=i;
printf (s=%u, s);
S se determine dac n este ptrat sau cub perfect.
Analiza problemei elaborarea algoritmului:
Pentru a verifica daca un numr este ptrat perfect calculam rdcina
ptrat a numrului
Daca numrul este ptrat perfect rdcina lui este un numr ntreg altfel
este un numr cu zecimale
Verificam daca ptratul partii ntregii a rdcinii numrului este egal cu
numrul dat, daca da numrul este ptrat perfect altfel numrul nu este ptrat
perfect
La fel procedam pentru a verifica daca un numr este cub perfect.
Program ptrat_i_cub_perfect; var n: longint;
BEGIN write (n=); readln (n); if n=trunc (sqrt (n)*trunc (sqrt (n) then
writeln (n, este ptrat perfect) else writeln (n, nu este ptrat perfect); if
n=trunc (exp (1/3*ln (n)*trunc (exp (1/3*ln (n)*trunc (exp (1/3*ln (n) then
writeln (n, este cub perfect) else writeln (n, nu este cub perfect); readln;
END.
/soluia n limbajul C include <stdio. H> include <math. H> unsigned
long n, m; void main (void){printf (n=); scanf (%lu, &n); m=pow (n, 0.5); if
(n=m*m) printf (n este ptrat perfect.); m=pow (n, 1. /3.); if (n=m*m*m) printf
(n este cub perfect.);
BEGIN write (Introduceti valoarea:); readln (x); xn: =1; repeat xn_1: =xn;
xn: =0.5*(xn_1+x/xn_1); until abs (xn-xn_1) <1e-5; writeln (radical din , xn:6:2,
=, sqrt (x):10:5); readln;
END.
/soluia n limbajul C include <stdio. H> include <math. H> float x, xn,
xn_1; void main (void){printf (Introducei valoarea:); scanf (%f, &x); xn=1; do
{xn_1=xn; xn=0.5*(xn_1+x/xn_1);
} while abs (xn-xn_1) <1e-5; printf (radical obinut =%7.5f, comparativ cu
%7.5, x, pow (x, 0.5);
Se citete n, s se determine toate numerele perfecte mai mici dect n.
Un numr este perfect dac este egal cu suma divizorilor si (de ex. 6=1+2+3).
Analiza problemei elaborarea algoritmului:
Pentru a verifica daca un numr este ptrat perfect trebuie sa i
determinam divizorii i sa verificam daca suma acestora este egala cu n
Se observa ca ultimul divizor nu trebuie luat n calcul pentru ca este egal
cu n
Pentru a afia toate numerele perfecte < n folosim un ciclu while n care il
decrementam pe n i verificam daca noul n este un numr perfect, daca da il
afiam program nr_perfecte; var n, d, i: word;
BEGIN write (n=); readln (n); while n>1 do begin dec (n); d: =0; for i: =1
to n-l do if n mod i=0 then d: =d+i; if n=d then writeln (n); end; readln;
END.
/o varianta C include <conio. H> include <stdio. H> main () long int i, n,
j, sum, k; clrscr (); printf (n=); scanf (%ld, &n); k=0; i=0; do
{k=k+1; do
{sum=1; i=i+1; for (j=2; j<=i/2; j+) if (i%j=0) sum=sum+j;
} while (sum! =i); printf (%ld , i);
} while (k<n);
Se citete n un numr ntreg pozitiv, s se afieze n transcris n baza 2.
Analiza problemei elaborarea algoritmului:
Folosim algoritmul cunoscut: ct timp n <>0 executa
mparte n la 2
n urma mpririi n retine catul i restul
Numrul n baza doi se obine scriind resturile n ordinea inversa n care
le-am obinut
Pentru a retine aceste resturi care trebuie tiprite n ordine inversa am
folosit un sir (n2inv) n care am reinut resturile pe care dup aceea l-am afiat
n ordine inversa.
Program transf_in_baza_2; var n, n2, i, j: word; n2inv: array [1.20] of
word;
BEGIN write (n=); readln (n); i: =1; while n>0 do begin n2: =n mod 2;
n2inv [i]: =n2; n: =n div 2; i: =i+1; end; for j: =i-l downto 1 do write (n2inv [j]);
readln;
END.
/o varianta C putin diferita include <stdio. H> typedef unsigned char
pointer [4]; void afieaz (pointer px, int dim, char* format){int i, j; for (j=dim-l;
j>=0; j-){for (i=8; i>=0; i-) printf (%c, px [j] & (1<i)? 1:0); putchar (.); printf (
adic ); printf (format, *px); float y; long x; void main (void){printf (. ntregul x
i realul y:); scanf (%d %f, &x, &y); printf (= ); afieaz (&x, sizeof (x),%d);
printf (= ); afieaz (&y, sizeof (y),%f);
Se citete n i irul de valori reale x1, x2 xn ordonate cresctor. S se
determine distana maxim ntre dou elemente consecutive din ir.
Analiza problemei elaborarea algoritmului:
Este o problema maxim
Distanta dintre primele valori consecutive din sir se noteaz cu max
Dup care facem o comparaie cu urmtoarele distante dintre valori
n momentul n care se ntlnete o valoare mai mare dect max atunci
aceasta valoare va deveni noul max
Algoritmul se oprete n momentul n care se face comparaia dintre max
i distanta dintre ultimele doua valori ale irului.
Program dist_elem; var n, i: word; max: real; x: array [1.50] of real;
BEGIN write (n=); readln (n); for i: =1 to n do begin write (x [, i, ] =);
readln (x [i]); end; max: =x [2]-x [1]; for i: =2 to n-l do if x [i+1]-x [i] >max then
max: =x [i+1]-x [i]; writeln (max=, max:6:2); readln;
END.
Se citete n gradul unui polinom i irul coeficienilor an a0. Se citete
x, s se determine P (x).
Program polinom; var n, i: integer; p, x: real; a: array [0.20] of integer;
BEGIN write (n=); readln (n); for i: =0 to n do begin write (a [, i, ] =);
readln (a [i]); end; write (x=); readln (x); p: =a [0]; for i: =1 to n do p: =p+a
[i]*exp (i*ln (x); writeln (P (, x, ) =, p:6:2);} p: =0; for i: =n downto 0 do p:
=p*x+a [i]; writeln (P (, x, ) =, p:6:2); readln;
END.
Se citete o propoziie (ir de caractere) terminat cu punct. S se
determine cte vocale i consoane conine propoziia.
Analiza programului elaborarea algoritmului:
Citim propoziia caracter cu caracter pana la ntlnirea caracterului .
Folosim instruciunea case (selecie multipla) care daca la ntlnirea unei
vocale din sir incrementeaz nr de vocale, iar la ntlnirea unei consoane
incrementeaz nr de consoane. Program nr_consoane_i_vocale; var c: char; i,
nv, ne: word; sir: string [25];
BEGIN write (Introduceti propoziia:); readln (sir); i: =1; nv: =0; ne: =0;
repeat case sir [i] of a, e, i, o, u: nv: =nv+1; b, c, d, f, g, h, j, k, l,
m, n, p, r, s, t, x, y, w: ne: =ne+1; end; i: =i+1; until sir [i] =.; writeln
(Nr de vocale=, nv); writeln (Nr de consoane=, ne); readln;
END.
/varianta C include <stdio. H> include <ctype. H> int i, vocale=0,
consoane=0; char c, sir [80]; void main (void){printf (Introd. Propoziia
terminata cu punct:); gets (sir); for (i=0; sir [i]! =.; i+) switch (toupper (sir
[i]){case A: case E: case I: case O: case U: vocale+; break; default: if (isalpha
(sir [i]) consoane+; printf (Vocale: %i, Consoane: %i, Alte car.: %i, vocale,
consoane, i-vocale-consoane);
} fclose (in); fclose (out); printf (Lungimea fs. Destinaie este de %ld
octei., contor);
/Copierea unui fiier text sursa ntr-un fiier destinaie
/cu substituirea unor cuvinte date prin linia de comanda include <stdio.
H> void main (int argc, char *argv [])
FILE *in, *out; char numfin [20], numfout [20], c; unsigned i=0, contor=0;
printf (Nume fiier sursa:); gets (numfin); printf (Nume fs. Destinaie:); gets
(numfout); if (in = fopen (numfin, rt) = NULL){fprintf (stderr, Eroare: %s fiier
inexistent., numfin); return;
} out = fopen (numfout, wt); while (! Feof (in){if (c=fgetc (in) =argv [1][i]){if
(argv [1][+i] =0) /s-a detectat sfritul irului de caractere fputs (argv [2], out),
i=0; /se scrie sirul de caractere nlocuitor
} else fputc (c, out); contor+;
} fclose (in); fclose (out); printf (Lungimea fs. Destinaie este de %d
octei., contor);
/prelucrarea unul fiier C ce conine o agenda telefonica include <stdio.
H> include <ctype. H> include <conio. H> struct articol char nume [10], adresa
[10], tel [7];
} inreg;
FILE *fagenda, *ftemp; char mod [3] =wb; void creare (void){char temp;
puts (agendei:); do {printf (:); gets (inreg. Nume); printf (Adresa:); gets
(inreg. Adresa); printf (Tel:); gets (inreg.tel); fwrite (&inreg, sizeof (inreg), 1,
fagenda); /* write struct inreg to file */printf (Continuai [D/N]?); temp=getch
();
} while (toupper (temp)! =N); /ciclu infinit? NU!
Fclose (fagenda); /* close file */void listare (void){int contor=0; puts
(agendei:); mod [0] =r; if (fagenda= fopen (agenda.jo, mod) = NULL) /* open
file agenda */fprintf (stderr, Cannot open output file.); while (fread (&inreg,
sizeof (inreg), 1, fagenda)! =0) /* write struct inreg to file */printf (%d: %s, %s,
%s, +contor, inreg. Nume, inreg. Adresa, inreg.tel); fclose (fagenda); /* close file
*/void main (void) if (fagenda= fopen (agenda.jo, mod) = NULL) /* open file
agenda */fprintf (stderr, Cannot open output file.); creare (); listare ();
Probleme ce necesit back-tracking
Am explicat pe larg aceast metod de programare ntr-un capitol
separat. n acest capitol vom oferi doar cteva exemple de probleme rezolvate.
Majoritatea dintre ele sunt de maxim dificultate i nu li se cunoate o altfel de
rezolvare dect prin aceast metod. Din fericire, aceast metod de proiectare
a soluiei are un caracter foarte general i funcioneaz n fiecare caz. Din
nefericire, n practic, atunci cnd dimensiunea datelor de intrare este
consistent (avnd valori cel puin de ordinul sutelor) programul rezultat
devine, prin durata astronomic de execuie, total inutilizabil.
Atragem atenia c doar simpla lecturare a acestor exemple de probleme
de back-tracking rezolvate nu permite nicidecum nsuirea acestei metode de
proiectare a soluiilor. Este necesar mai nti implicarea i participare
personal, a celui ce-i propune s nvee aceast metod, ncercnd direct
soluionarea lor i abia apoi comparnd soluia rezultat cu cea propus de noi.
scanf (%i, &s); descompune (s, 1,0); if (nrmin>0) for (i=1; i<=kmin; i+) printf
(%i * %i,, a_final [i], m [i]); else puts (Nu se poate descompune!);
S se afieze toate descompunerile unui numr s ca sum de n elemente.
De exemplu, pentru s=13 i n=3 avem urmtoarele 14 descompuneri 13=
1+1+11= 1+2+10= 1+3+9=. = 1+6+6= 2+2+9= 2+3+8= 2+4+7= 2+5+6= 3+3+7=
3+4+6= 3+5+5= 4+4+5
Dei este cu totul alt problem dect cea dinainte, putem observa
asemnarea dintre cele dou soluii (ambele sunt date n varianta recursiv)
include <stdio. H> int a [10], s, n, contor=0; void descompune (int s, int
k){register int i; if (k=1){a [n] =s; printf (%3i:, +contor); for (i=1; i<=n; i+) printf
(%i , a [i]); puts (); return;
} else for (i=1; i<s; i+){a [n+l-k] =i; descompune (s-l, k-l);} void main
(void){printf (Introd. Suma s i n ct se descompune n:); scanf (%i %i, &s,
&n); descompune (s, n); getchar ();
S se afieze toate descompunerile unui numr s ca sum de n elemente
distincte.
Aceasta este o variant a problemei dinainte; putei sesizai unde apare
diferena n rezolvare?
Include <stdio. H> int a [10], s, n, contor=0; void descompune (int s, int
k){register int i; if (k=0){printf (%3i:, +contor); for (i=1; i<=n; i+) printf (%4i, a
[i]); puts (); return;
} else for (i=a [n-k]+1; i<s; i+){a [n+l-k] =i; descompune (s-l, k-l);} void main
(void){printf (Introd. Suma s i n ct se descompune n:); scanf (%i %i, &s,
&n); a [0] =0; descompune (s, n); if (contor=0) puts (Nu se poate
descompune!); getchar ();
Probleme cu soluie surprinztoare
n rezolvarea fiecreia din problemele urmtoare este foarte uor de czut
n capcana soluionrii de genul la prima mn sau brute-force-approach n
limba englez (abordare n for brut). Este cea mai des ntlnit capcan
pentru programatorii lipsii de subtilitate, experien sau cultur de
specialitate. Este i aceasta o rezolvare, desigur, dar lipsa ei de eficien i de
elegan este evident. Tocmai de aceea, considerm foarte util prezentarea
ctorva exemple elocvente, mpreun cu soluiile lor. Unele dintre probleme au
fost selecionate dintre problemele date la concursurile i olimpiadele colare de
programare.
Prin acest capitol nu urmrim doar nsuirea unor cunotine practice de
programare ci, mai ales, aprofundarea capacitii de analiz i proiectare a
soluiilor. Aceasta presupune un salt calitativ n nvarea programrii i de
aceea acest capitol devine cu adevrat util numai pentru acei programatori
inteligeni i dornici de auto-perfecionare. Sau pentru cei care se pregtesc
pentru participarea la concursurile i olimpiadele de informatic.
Soluiile oferite de noi sunt, pentru fiecare problem, eficiente i
elegante. Acest fapt se datoreaz accentului pus pe aprofundarea i
mbuntirea primei analize a problemei.
Putem atunci spune, c motto-ul acestui capitol este: Nu te mulumi
niciodat cu soluia la prima mn!.
=keypressed; inc (i); until (i=viteza) or ok; if ok then begin tasta: =readkey; if
tasta = #0 then tasta: =readkey; mutapaleta1; mutapaleta2; end;
Paleta1(#219);
Paleta2(#219); scr [y, x]. Car: = ; scr [y, x]. Car: = ; end else begin sound
(800); if (x>=80) and (y>9) and (y<17) then d: =d+1; if (x<=1) and (y>9) and
(y<17) then s: =s+1; textcolor (2); textbackground (7); gotoxy (39,2); write
(SCOR); gotoxy (38,3); write ( , d, : , s); if (d=5) or (s=5) then begin gotoxy
(35,10); write ( G A M E O V E R ); cntec; nosound; halt; end; delay (1500);
paleta1( ); paleta2( ); x0: =40; y0: =13; u: =20*PI/180; {reiniializare micare
minge} x: =x0; y: =y0; for i: =1 to 5 do begin yP1[i]: =10+i; yP2[i]: =10+i; uP [i]: =
(i/3*PI-PI)/5; end; tasta: = ; nosound; end; until tasta=#27;
End.
Program Biliard; {demonstrativ pentru folosirea modului grafic} uses
Graph, Crt;
Const nr_obiecte=10; raza=25; pasx=3; pasy=2; viteza=10; {de la 0 la 10}
var grDriver, grMode, ErrCode: Integer; i, xMax, yMax, xtmp, ytmp: word; x, y:
Array [1. Nr_obiecte] of word; sensx, sensy: Array [1. Nr_obiecte] of shortint;
Procedure Deseneaz (x, y, color: word);
Const buci=12;
Var x1, y1, unghi, Xasp, Yasp: word;
Begin
SetWriteMode (XORPut); SetColor (color);
GetAspectRatio (Xasp, Yasp); unghi: =0; x1: =x+Trunc (raza*cos
(unghi*2*PI/buci); y1: =y+Trunc (raza*sin (unghi*2*PI/buci)*Xasp/Yasp);
For unghi: =1 to buci do begin xtmp: =x+Trunc (raza*cos
(unghi*2*PI/buci); ytmp: =y+Trunc (raza*sin (unghi*2*PI/buci)*Xasp/Yasp);
Line (x1, y1, xtmp, ytmp); Line (x, y, x1, y1); x1: =xtmp; y1: =ytmp; end;
End; begin grDriver: = Detect;
InitGraph (grDriver, grMode,);
ErrCode: = GraphResult; if ErrCode = grok then begin {Do graphics}
xMax: =GetMaxX; yMax: =GetMaxY;
Rectangle (0,0, xMax, yMax);
Randomize;
For i: =1 to nr_obiecte do begin x [i]: =raza+Random (xMax-2*raza); y [i]:
=raza+Random (yMax-2*raza); sensx [i]: =-l+(i mod 2)*2; sensy [i]: =-sensx [i];
Deseneaz (x [i], y [i], i); end;
Repeat
For i: =1 to nr_obiecte do begin
Deseneaz (x [i], y [i], i); xtmp: =x [i]+pasx*sensx [i]; ytmp: =y
[i]+pasy*sensy [i];
If (xtmp>raza) and (xtmp<xMax-raza) then x [i]: =xtmp else sensx [i]: =sensx [i];
If (ytmp>raza) and (ytmp<yMax-raza) then y [i]: =ytmp else sensy [i]: =sensy [i];
Deseneaz (x [i], y [i], i);
Delay (100-l0*viteza); end;
Until KeyPressed;
Readln;
CloseGraph; end else
Writeln (Graphics error:, GraphErrorMsg (ErrCode); end.
/Program C de umplere a ecranului text prin acces direct la memoria
ecran include <dos. H> include <conio. H> struct scrcar {unsigned char car,
atrib;
} far *ecran; int lin, col; int culoare=BLUE, fundal=LIGHTGRAY; void main
(void){ecran= (struct scrcar far *) MK_FP (0xb800,0); for (lin=0; lin<25; lin+) for
(col=0; col<80; col+) {ecran [lin*80+col]. Car=*; ecran [lin*80+col].
Atrib=fundal*16+culoare;
} getch ();
Program Acces_direct_ecran_grafic320_200;
{Fiecare jumtate de ecran se genereaz din cealalt jumtate pe baza
proprietilor automatelor celulare asemntor ca n jocul Life}
Uses crt;
Const maxl=200-l; maxc=320-l; mijl=maxc div 2;
Type Matrice=array [0. Maxl, 0. Maxc] of byte; var scr: Matrice absolute
$A000:0; {adresa memoriei ecran n modul grafic 320x200} i, j, k, l, c, x: integer;
ok: char;
BEGIN asm {iniializeaz n mod grafic 320x200x250 NU n
640x400x256} mov ah, 0 mov al, 13h int 10h; end; randomize; x: =random
(maxc); for k: =1 to 2 do for i: =0 to maxl do for j: =0 to mijl do scr [i, j+k*mijl]:
=random (maxc); k: =0; repeat repeat for i: =0 to maxl do for j: =0 to mijl do
begin l: =i; c: =j+k*mijl; if (scr [(l-l) mod maxl, c] <scr [l, c]) and scr [l, (c-l) mod
mijl] <scr [l, c]) then scr [i, j+(k+1) mod 2)*mijl]: = (scr [(l-l) mod maxl, c]+scr [l,
(c-l) mod mijl]+ x) div 3-l else if (scr [l, (c+1) mod mijl] >scr [l, c]) and scr [(l+1)
mod maxl, c] >scr [l, c]) then scr [i, j+(k+1) mod 2)*mijl]: = (scr [(l+1) mod maxl,
c]+scr [l, (c+1) mod mijl]+ x) div 3+1 else scr [i, j+(k+1) mod 2)*mijl]: =scr [l, c]+1;
end; k: = (k+1) mod 2; until keypressed; ok: =readkey; x: =random (maxc); if
ok<>#27 then ok: =readkey; until ok=#27; readln;} asm {nchide modul grafic}
mov ax, 0 int 10h end;
END.
Program Mouse; {Gestionarea mouse-ului prin apelul ntreruperii de
sistem $33} uses Crt, Graph, Dos; var grDriver, grMode, ErrCode: Integer;
mfunc, buton, mx, my, xf, yf, x, y: word; xi, yi: integer; s1, s2, s3: string [5];
P: pointer;
Size: Word;
{ntr $33, nR. Fctiei dorite n AX:
00 mouse reset
01 cuplare cursor mouse (vizibil)
02 decuplare cursor mouse (ascuns)
03 determ. Unei apsri pe tasta i semnalare poziie
04 poziionarea cursorului de mouse
05 inforM. Suplim. Despre apsarea tastelor
06 inreg. Tastelor de mouse eliberate
sega, segb: word; pagfun: pointer; bytes, width, height: word; charw, charh,
planes, bits, nbanks, model, sbank, nrimpg, reservb, rms, rfp, gms, gfs, bms,
bfs: byte; reserv: array [1.512] of byte end; function hexa (v: word): string; const
s: string [16] =0123456789abcdef; function hexb (b: byte): string; begin hexb:
=s [b div 16+1]+s [b mod 16+1]; end; begin hexa: =hexb (hi (v)+hexb (lo (v); end;
procedure setbank (b: longint); begin vseg: =$a000; if b<>cbank then with rg,
vesamod do begin cbank: =b; ax: =$4f05; bx: =0; dx: =b*64 div gran; ntr (16,
rg); end; end; procedure putpixel (x, y: word; cul: longint); var l: longint; m, z:
word; begin with rg, vesamod do case bits of
4: begin l: =longint (bytes)*y+x div 8; port [$3ce]: =3; port [$3cf]: =0; port
[$3ce]: =5; port [$3cf]: =2; port [$3ce]: =8; port [$3cf]: =128 shr (x and 7);
setbank (l shr 16); z: =mem [vseg: word (l)]; mem [vseg: word (l)]: =cul; end;
8: begin l: =longint (bytes)*y+x; setbank (l shr 16); mem [vseg: word (l)]:
=cul; end;
15,16: begin l: =longint (bytes)*y+x*2; setbank (l shr 16); memw [vseg:
word (l)]: =cul; end;
24: begin l: =longint (bytes)*y+x*3; z: =word (l); m: =l shr 16; setbank (m);
if z<$fffe then move (cul, mem [vseg: z], 3) else begin mem [vseg: z]: =lo (cul); if
z=$ffff then setbank (m+1); mem [vseg: z+1]: =lo (cul shr 8); if z=$fffe then
setbank (m+1); mem [vseg: z+2]: =cul shr 16; end; end; end; end; begin with rg,
vesabuf, vesamod do begin ax: =$4f00; es: =seg (vesabuf); di: =ofs (vesabuf);
sign: =$41534556; ntr (16, rg); if al<>$4f then begin writeln (Standardul VESA
nu e implementat); exit end; imod: =1; while list^ [imod] <>$ffff do begin ax: =3;
ntr (16, rg); ax: =$4f01; cx: =list^ [imod]; es: =seg (vesamod); di: =ofs (vesamod);
ntr (16, rg); if attr and 16<>0 then begin writeln (oem, VESA Versiune , hi
(vers), ., lo (vers); writeln (hexa (list^ [imod]), Rezoluie: , width, x , height,
Culori: , longint (1) shl bits); write (Doriti testare (D/N)? ); readln (opt); end
else opt: =N; if upcase (opt) =D then begin ax: =$4f02; bx: =list^ [imod]; ntr
(16, rg); cbank: =-l; ntbanks: =longint (bytes)*height div gran div 1024; for x: =0
to ntbanks do begin setbank (x); mem [$a000: $ffff]: =0; fillchar (mem [$a000:0],
$ffff, 0); end; case bits of
4,8: c: =15;
15: c: =32767;
16: c: =65535;
24: c: =longint (1) shl 24-l; end; for x: =0 to width-l do begin putpixel (x,
0, c); putpixel (x, height-l, c); end; for y: =0 to height-l do begin putpixel (0, y, c);
putpixel (width-l, y, c); end; for x: =0 to 191 do for y: =0 to 191 do begin case
bits of
4: c: = (y div 48)*4+x div 48;
8: c: = (y div 12)*4+x div 12;
15,16: c: = (y div 6)*(1 shl rfp)+x div 6;
24: c: =longint (x)*65536+y; end; putpixel (x+4, y+4, c); end; readln; end;
inc (imod); end; ax: =3; ntr (16, rg); end; end.
Curioziti i trucuri de programare
Pentru o ct mai complet prezentare a programrii n C nu puteam evita
prezentarea unor curioziti i ale unor trucuri de programare C. Acelai lucru
este valabil i pentru limbajul Pascal dar este acesta este oarecum ieit din
mod. Numrul foarte mare de astfel de invenii a condus la organizarea nc
din 1984 a unui concurs internaional de programare numit foarte sugestiv The
International Obfuscated C Code Contest IOCCC adic Concursul
internaional de programare ofuscat C (nclcit i confuz). Participanii la
acest concurs ofer n fiecare an adevrate perle de programare C ce dovedesc,
pe lng serioase cunotine de C, aptitudinile extraordinare i fiabilitatea
compilatorului C. Multe din capodoperele acestui concurs au fost apoi
inscripionate pe tricouri sau pungi, spre deliciul fanilor programrii C.
Aceast pasiune are totui i o latur serioas ce poate fi sesizat n
programarea sub platformele (sistemele de operare) gen Unix. n aceste sisteme
toate programele circul nu numai sub forma de cod executabil ci i n sursa
original C. Ascunderea unor informaii despre programarea sistem de ochii
celor periculos de curioi este astfel dificil. Dar iat c acest tip de
programare ofuscat face acest lucru posibil! Numai cei foarte pasionai i
prind urechile n descifrarea unor astfel de programe intenionat nclcite.
Altfel spus, secretul unor astfel de programe se ascunde chiar n rebusul din
faa ochilor cititorului.
Recomandm acest capitol n special fanilor programrii C i celor foarte
pasionai.
/Un simplu Hello world! dar care arata o surprinztoare interpretare a
compilatorului C include <stdio. H> char a [] =Hello world!; int i; void main
(void){for (i=0; a [i]! =; i+) putchar (i [a]); /! A [i] <=> *(a+i) <=> *(i+a) <=> i [a]!
/Iat unde conduce folosirea tipului de date float:
/c este foarte diferit de w?!
/Putem spune ca acesta este un bug al C-ului?
Include <stdio. H> float a=12345679., b=12345678., c=a*a-b*b, u=a*a,
v=b*b, w=u-v; void main (){printf (a=%f, b=%f=%f, w=%f, a, b, c, w);
/Iat i varianta corecta n care nu se produce nici o trunchiere:
include <stdio. H> long double a=12345679., b=12345678., c=a*a-b*b, u=a*a,
v=b*b, w=u-v; void main (){printf (a=%Lf, b=%Lf=%Lf, w=%Lf, a, b, c, w);
/Acest program este capabil s-i duplice identic la ieire codul sursa C
fara a efectua nici o
/citire de nicieri. Are deci caracteristica unui virus, se auto-replica!
Include <stdio. H> char *s [] = { #include <stdio. H>, char *s [] = {, void
main (void){, int i; char *ps;, puts (s [0]); puts (s [1]);, for (i=0; i<10; i+),
{putchar (34); for (ps=s [i]; *ps; ps+) putchar (*ps);, putchar (34); putchar (, );
putchar (10);}, putchar (34); for (ps=s [10]; *ps; ps+) putchar (*ps); putchar
(34); putchar (10);, putchar (} ); putchar (;); putchar (10);, for (i=2; i<11; i+)
puts (s [i]); putchar (} );
}; void main (void){int i; char *ps; puts (s [0]); puts (s [1]); for (i=0; i<10; i+)
{putchar (34); for (ps=s [i]; *ps; ps+) putchar (*ps); putchar (34); putchar
(, ); putchar (10);} putchar (34); for (ps=s [10]; *ps; ps+) putchar (*ps); putchar
(34); putchar (10); putchar (} ); putchar (;); putchar (10); for (i=2; i<11; i+) puts
(s [i]); putchar (} );
/Program C surpriza (ales dintre cele de la IOCCC)
SFRIT