Psihologia concursurilor de informatică/1 Concursul de informatică

From Algopedia
Jump to: navigation, search

⇦ înapoi la Psihologia concursurilor de informatică

Capitolul I: Concursul de informatică (de la extaz la agonie)

Cine dorește să-și rezolve treburile la vremea potrivită, să-și împartă cu atenție timpul
— Plaut

Experiența demonstrează că, oricât de mare ar fi bagajul de cunoștințe acumulat de un elev, mai e nevoie de ceva pentru a-i asigura succesul la olimpiada de informatică. Aceasta deoarece în timp de concurs lucrurile stau cu totul altfel decât în fața calculatorului de acasă sau de la școală. Reușita depinde, desigur, în cea mai mare măsură de puterea fiecăruia de a pune în practică ceea ce a învățat acasă. Numai că în acest proces intervin o serie de factori care țin de temperament, de experiența individuală, de numărul de ore dormite în noaptea dinaintea concursului (care în taberele naționale este îngrijorător de mic) și așa mai departe.

Cu riscul de a cădea în demagogie, trebuie să spunem că un concurs de informatică presupune mult mai mult decât un simplu act de prezență la locul desfășurării ostilităților. Capitolul de față încearcă să enunțe câteva principii ale concursului, pe care autorul și le-a însușit în cei patru ani de liceu, atât din experiența proprie, cât și învățând de la alții. Cititorul este liber să respingă aceste sfaturi sau să le accepte, filtrându-le prin prisma personalității sale și alegând ceea ce i se potrivește.


Înainte de concurs

Primul și cel mai de seamă lucru pe care trebuie să îl știți este că e important și să participi, dar e și mai important să participi onorabil, iar dacă se poate să și câștigi. Nu trebuie să porniți la drum cu îngâmfare; modestia e bună, dar nu trebuie în nici un caz să ducă la neîncredere în sine. Fiecare trebuie să știe clar de ce e în stare și, mai presus de toate, să se gândească că la urma urmei nu dificultatea concursului contează, căci concursul, greu sau ușor, este același pentru toți. Mult mai importantă este valoarea individuală și nu în ultimul rând pregătirea psihologică.

Autorul a fost peste măsură de surprins să constate că mulți elevi merg la concurs fără ceas și fără hârtie de scris. Aceasta este fără îndoială o greșeală capitală. În timpul concursului trebuie ținută o evidență drastică a timpului scurs și a celui rămas. E drept că în general supraveghetorii anunță din când în când timpul care a trecut, dar e bine să nu vă bazați pe nimeni și nimic altceva decât pe voi înșivă. Unii colegi spuneau „Ei, ce nevoie am de ceas, oricum am ceasul calculatorului la îndemână”. Așa e, dar e extrem de incomod să te oprești mereu la jumătatea unei idei, să deschizi o sesiune DOS din cadrul limbajului de programare și să afli cât e ceasul.

În ceea ce privește hârtia de scris, ea este în mod sigur necesară. De fapt, o parte importantă a rezolvării unei probleme este proiectarea matematică a algoritmului, lucru care nu se poate face decât cu creionul pe hârtie. Pe lângă aceasta, majoritatea problemelor operează cu vectori, matrice, arbori, grafuri etc., iar exemplele pe care este testat programul realizat trebuie neapărat verificate „de mână”. E de preferat să aveți hârtie de matematică; este foarte folositoare pentru problemele de geometrie analitică, precum și pentru reprezentarea matricelor. Cantitatea depinde de imaginația fiecăruia. În unele cazuri speciale, autorului i s-a întâmplat să umple 7-8 coli A4.


În timpul concursului

Din fericire pentru unii și din nefericire pentru alții, majoritatea examenelor îți cer să dovedești nu că ești bine pregătit, ci că ești mai bine pregătit decât alții. Aceasta înseamnă că și la olimpiada de informatică se aplică legea peștelui mai mare sau, cum i se mai spune, a concurenței. Valoarea absolută a fiecăruia nu contează chiar în totalitate, ceea ce constituie sarea și piperul concursului. Într-adevăr, ce farmec ar avea să mergi la un concurs la care se știe încă dinainte cine este cel mai bun ? Este destul de amuzant să observi cum fiecare speră să prindă „o zi bună”, iar adversarii săi „o zi proastă”.

Este ușor să fii printre cei mai buni atunci când concursul este ușor. Mai greu e să fii cel mai bun atunci când concursul este dur, pentru că atunci intervine - inevitabil - dramul de noroc al fiecăruia. Niciodată însă nu se poate invoca greutatea concursului drept o scuză pentru un eventual eșec. Concursul este la fel de greu pentru toți. Se poate întâmpla, mai ales dacă probele durează mai multe zile (3-4) ca nici unul din concurenți să nu acumuleze mai mult de 70-80% din punctajul maxim. Totuși, aceasta nu înseamnă că ei nu sunt bine pregătiți; mai mult, unul dintre ei trebuie să fie primul. Așadar, niciodată nu trebuie adoptată o strategie de genul „problema asta e grea și n-am s-o pot rezolva perfect, așa că nu mă mai apuc deloc de ea”. Nu trebuie să vă impacientați dacă vi se întâmplă să nu aveți o idee genială de rezolvare a unei probleme. Nu vă cere nimeni să faceți perfect o problemă, ci numai să prezentați o soluție care să acumuleze cât mai multe puncte. Evident, prima variantă este întotdeauna preferabilă, dar nu obligatorie.

De multe ori se întâmplă ca un elev să găsească o soluție cât de cât bună la o problemă și, măcar că știe că nu va lua punctajul maxim, ci doar o parte, să renunțe să caute o soluție mai eficientă, deoarece timpul pierdut astfel ar aduce un câștig prea mic și ar putea fi folosit la rezolvarea altor probleme. Desigur, dacă nu faci toate problemele perfect, nu mai poți fi sigur de premiul I, pentru că altcineva poate să te întreacă. Dar pe de altă parte, locul pe care te clasezi contează numai la etapa națională a olimpiadei sau la concursurile internaționale. În rest, important e numai să te califici, adică să intri în primele câteva locuri.

Feriți-vă ca de foc de criza de timp. E mare păcat să ratezi o problemă întreagă pentru că n-ai avut timp să scrii procedura de afișare a soluției. Rezervați-vă întotdeauna timpul pe care îl socotiți necesar pentru implementare și depanare.

Niciodată, chiar dacă concursul este ușor, nu e bine să ieșiți din sala de concurs înainte de expirarea timpului. Oricât ați fi de convinși că ați făcut totul perfect, mai verificați-vă; veți avea de furcă cu remușcările dacă descoperiți după aceea că ceva, totuși, nu a mers bine. Puteți face o mulțime de lucruri dacă mai aveți timp (deși acest lucru se întâmplă rar). Iată o serie de metode de a exploata timpul:

  • Verificați-vă programul cu cât mai multe teste de mici dimensiuni. Să presupunem că programul vostru lucrează cu vectori de maxim 10000 de elemente. E o idee bună să îl rulați pentru vectori de unul sau două elemente. Nu se știe cum pot să apară erori.
  • Treceți la polul opus și creați-vă un test de dimensiune maximă, dar cu o structură particulară, pentru care este ușor de calculat rezultatul și de mână. De exemplu, vectori de 10000 elemente cu toate elementele egale, sau vectori de forma (1, 2, ..., 9999, 10000). Dacă nu puteți să editați un asemenea fișier de mână, copiind și multiplicând blocuri, puteți scrie un program care să-l genereze.
  • Dacă încă v-a mai rămas timp, creați-vă un program care să genereze teste aleatoare. Spre exemplu, un program care să citească un număr N și să creeze un fișier INPUT.TXT în care să scrie N numere aleatoare. Într-o primă fază, puteți folosi aceste teste pentru a verifica dacă nu cumva la valori mai mari programul nu dă eroare, nu se blochează (la alocarea unor zone mari de memorie) sau nu depășește limita de timp, caz în care mai aveți de lucru.
  • Dacă tot nu vă dă nimeni afară din sală, puteți scrie un alt program auxiliar care, primind fișierul INPUT.TXT și fișierul OUTPUT.TXT produs de programul vostru, verifică dacă ieșirea este corectă. Aceasta deoarece, de obicei, este mult mai ușor de verificat o soluție decât de produs una (sau, cum spunea Murphy, „cunoașterea soluției unei probleme poate ajuta în multe cazuri la rezolvarea ei”). Folosind „generatorul” de teste și „verificatorul”, puteți testa programul mult mai bine. De altfel, la multe probleme chiar testele rulate de comisia de corectare sunt create tot aleator.
  • În caz că ați dat o soluție euristică la o problemă NP-completă, puteți implementa și un backtracking ca să vedeți cât de bune sunt rezultatele găsite euristic. Apoi, puteți începe să modificați funcția euristică pentru a o face cât mai performantă.

Și, ca să nu mai lungim vorba, iată o strategie care pare să dea rezultate:

A

Imediat ce primiți problemele, citiți toate enunțurile și făceți-vă o idee aproximativă despre gradul de dificultate al fiecărei probleme. Neapărat verificați dacă se dau limite pentru datele de intrare (numărul maxim de elemente ale unui vector și valoarea maximă a acestora, numărul maxim de noduri dintr-un graf etc.) și pentru timpii de execuție pentru fiecare test. Dacă nu se dau, întrebați imediat. Dimensiunea input-ului poate schimba radical dificultatea problemei. Spre exemplu, pentru un vector cu N=100 elemente, un algoritm O(N^{3}) merge rezonabil, pe când pentru N=10000 același algoritm ar depăși cu mult cele câteva secunde care se acordă de obicei. Fair-play-ul cere să puneți întrebările cu voce tare, pentru ca și ceilalți să audă; de altfel, nu aveți nici un motiv să vă feriți de ceilalți concurenți. Cei care sunt interesați de aceste întrebări le-ar pune oricum și ei, iar cei care nu sunt interesați vor ignora oricum răspunsul.

Dacă există probleme care cer să se găsească un optim (maxim/minim) al unei valori, întrebați dacă se acordă punctaje parțiale pentru soluții neoptime. Și acest fapt poate schimba natura problemei. După aceasta,

Nr_probleme_nerezolvate := Nr_probleme_primite;

while (Nr_probleme_nerezolvate>0) 
      and not ("Timpul a expirat, va rugam sa salvati") do
begin

B

Faceți o împărțire a timpului pentru problemele rămase proporțional cu punctajul fiecărei probleme. În general problemele au punctaje egale, dar nu totdeauna. De exemplu, dacă o problemă e cotată cu 100 puncte, iar alta cu 50, veți aloca de două ori mai mult timp primei probleme, chiar dacă nu vi se pare prea grea. Încercați să nu depășiți niciodată limitele de timp pe care le-ați fixat. Dacă în schimb reușiți să economisiți timp față de cât v-ați propus, cu atât mai bine, veți face o realocare a timpului și veți avea mai mult pentru celelalte probleme.

C

Apucați-vă de problema cea mai simplă, chiar dacă e punctată mai slab. Mai bine să duceți la bun sfârșit o problemă ușoară și să luați un punctaj mai mic, decât să vă apucați de o problemă grea și să nu terminați niciuna. Dacă toate problemele par grele, alegeți-o pe cea din domeniul care vă este cel mai familiar, în care ați lucrat cel mai mult. Dacă vă este indiferent și acest lucru, alegeți o problemă unde simțiți că aveți o idee simplă de rezolvare. Dacă, în sfârșit, nu aveți nici o idee la nici o problemă, apucați-vă de cea mai bine punctată.

D

Citiți din nou enunțul, de data aceasta cu mare grijă. Întrebați supraveghetorul pentru orice nelămurire. Dacă anumite lucruri nu sunt specificate, iar profesorul nu vă dă nici un fel de informații suplimentare, tratați problema în cazul cel mai general. Iată mai multe exemple frecvente în care enunțul nu este limpede:

  • Dacă nu se precizează cât de mari pot fi întregii dintr-un vector, nu lucrați pe Integer, nici pe Word, ci pe LongInt;
  • În problemele de geometrie analitică, e bine să presupuneți că punctele nu au coordonate întregi, ci reale;
  • De asemenea, pătratele și dreptunghiurile nu au neapărat laturi paralele cu axele, ci sunt așezate oricum în plan (aceasta poate într-adevăr să complice extrem de mult problema; nu vă doresc să vă izbiți de o asemenea neclaritate...);
  • Dacă fișierul de intrare conține string-uri, să nu presupuneți că ele au maxim 255 de caractere. Mai bine scrieți propria voastră procedură de citire a unui string, care să citească din fișier caracter cu caracter până la Eoln, decât să aveți surprize. Dacă S este o variabilă de tip String, ReadLn(S) ignoră tot restul rândului care depășește lungimea lui S.
  • Grafurile nu sunt neorientate, ci orientate. În principiu, enunțul nu are voie să fie neclar în această privință, dar au existat cazuri de neînțelegere.

E

Începeți să vă gândiți la algoritmi cât mai buni, estimând în același timp și cât v-ar lua ca să-i implementați. Faceți, pentru fiecare idee care vă vine, calculul complexității. Nu trebuie neapărat să găsiți cel mai eficient algoritm, ci numai unul suficient de bun. În general, trebuie ca, dintre toți algoritmii care se încadrează în timpul de rulare, să-l alegeți pe cel care este cel mai ușor de implementat. Iată un exemplu:

  • Să presupunem că timpul de testare este de 5 secunde, lucrați pe un 486DX4, algoritmul vostru are complexitatea O(N^{3}), iar N este maxim 100. Un 486 face câteva milioane de operații elementare pe secundă, să zicem 4.000.000. Aceasta înseamnă ceva mai puține operații mai costisitoare (atribuiri, comparații etc.) pe secundă. Să ne oprim deci la cifra de 1.000.000. Programul vostru are timp de rulare cubic, iar N^{3} este maxim 1.000.000. De aici deducem că programul ar trebui să se încadreze într-o secundă. Calculul nostru este grosier, dar luând și o marjă de eroare arhisuficientă, rezultă că programul trebuie să meargă cu ușurință în 5 secunde, deci algoritmul este acceptabil.

F

Dacă algoritmul găsit este greu de implementat, mai căutați un altul o vreme. Trebuie însă ca timpul petrecut pentru găsirea unui nou algoritm plus timpul necesar pentru scrierea programului să nu depășească timpul necesar pentru implementarea primului algoritm, altfel nu câștigați nimic. Deci nu exagerați cu căutările și nu încercați să reduceți dincolo de limita imposibilului complexitatea algoritmului. Mai ales, nu uitați că programul nu poate avea o complexitate mai mică decât dimensiunea input-ului sau a output-ului. De exemplu, dacă programul citește sau scrie matrice de dimensiune N\times N, nu are sens să vă bateți capul ca să găsiți un algoritm mai bun decât O(N^{2}).

G

Dintre toate ideile de implementare găsite (care se încadrează fără probleme în timp), o veți alege pe cea mai scurtă ca lungime de cod. De exemplu:

  • Dacă N\leq 1000 și dispuneți de doi algoritmi, unul pe care îl estimați cam la 200 de linii de program, de complexitate O(N\log N) și unul de 100 de linii de complexitate O(N^{2}), cel de-al doilea este evident preferabil, pentru că nu pierdeți nimic din punctaj, sau cel mult pierdeți un test prin cine știe ce întâmplare, în schimb câștigați timp prețios pe care îl puteți folosi pentru alte probleme. Bineînțeles, primul program este mai eficient, dar în condiții de concurs el este prea eficient. Este o mândrie să faceți o problemă perfect chiar dacă ratați o alta, dar este un câștig și mai mare să faceți amândouă problemele suficient de bine.

H

În general, pentru orice problemă există cel puțin o soluție, fie și una slabă. Sunt numeroase cazurile când nici nu vă vine altă idee de rezolvare decât cea slabă. De regulă, când nu aveți în minte decât o rezolvare neeficientă a problemei, care știți că nu o să treacă toate testele (un backtracking, sau un O(N^{5}), O(N^{6}) etc.), e bine să încercați următorul lucru:

  • Să presupunem că v-a mai rămas o oră pentru rezolvarea acestei probleme. Calculați cam cât timp v-ar trebui ca să implementați rezolvarea slabă. Să zicem 40 de minute. În acest calcul trebuie să includeți și timpul de depanare a programului (care variază de la persoană la persoană) și pe cel de testare. Dacă sunteți foarte siguri pe voi, puteți să neglijați timpul de testare, dar orice program trebuie testat cel puțin pe exemplul de pe foaie.
  • Mai rămân deci 20 de minute, timp în care vă puteți gândi la altceva, la altă soluție. Pentru a avea șanse mai mari să găsiți o altă soluție, este indicat să încercați să ignorați complet soluția slabă, să nu o luați ca punct de plecare. Încercați să vă „goliți” mintea și să găsiți ceva nou, altfel vă veți învârti mereu în cerc.
  • Dacă vă vine vreo idee mai bună, ați scăpat de griji și mergeți la punctul (F). Altfel, la expirarea timpului de 20 de minute, vă apucați să implementați soluția pe care o aveți, oricât de ineficientă ar fi (de fapt, orice soluție, oricât de ineficientă, trebuie să ia măcar o treime sau o jumătate din punctaj, dacă nu apar erori de implementare).
  • Puteți, ca o măsură extremă, să depășiți cu maxim 5 minute cele 20 de minute planificate, dar de cele mai multe ori acesta e timp pierdut, deoarece intervine stresul și nu puteți să vă mai concentrați.

I

Dacă ați ajuns până aici înseamnă că ați optat pentru o variantă de implementare. Din acest moment, pentru această variantă veți scrie programul, fără a vă mai gândi la altceva, chiar dacă pe parcurs vă vin alte idei. Iată unele lucruri pe care e bine să le știți despre scrierea unui program:

  • Datele de intrare se presupun a fi corecte. Aceasta este o regulă nescrisă (uneori) a concursului de informatică. Chiar dacă, prin absurd, știți sigur că datele de intrare trebuie verificate, mai bine n-o faceți, din mai multe motive. În primul rând, scopul cu care v-a fost dată problema este altul decât să se constate cine verifică mai bine datele de intrare. De aceea, cel mult un test sau două vor fi cu date greșite. În al doilea rând, nu se justifică să risipiți atâta timp numai pentru câteva puncte pe care le-ați putea pierde dacă nu faceți verificarea. În al treilea rând, e posibil să greșiți oricum problema în sine, caz în care nu mai contează dacă ați citit perfect datele de intrare. În sfârșit, legea lui Murphy spune că „oricâte teste ar efectua cineva asupra datelor de intrare, se va găsi cineva care să introducă date greșite”. Efortul este deci zadarnic...
  • Ultimul lucru, când sunteți convinși că programul este terminat și când v-ați hotărât să nu îl mai modificați, adăugați opțiunile de compilare. Puteți face aceasta apăsând Ctrl-O-O. La începutul programului vor apărea directivele de compilare. Setați $B, $I, $R și $S pe - (minus). Eventual, puteți include direct linia {$B-,I-,R-,S-} imediat după titlul programului. Aceasta va face compilatorul să nu mai evalueze complet expresiile booleene, să nu mai verifice operațiile de intrare/ieșire, domeniul de atribuire (Range Checking) și stiva (Stack Checking). Există două avantaje majore: în primul rând că programul merge mai repede (se câștigă câteva procente bune la viteză), iar în al doilea rând, psihologic vorbind, este preferabil ca un program să se blocheze decât să se oprească printr-un banal „Range check error”. Nu vă grăbiți să puneți directivele de compilare încă de la început, deoarece nu veți mai primi mesajele corespunzătoare de eroare și vă va fi mai greu să depanați programul.
  • Pe cât este posibil, încercați să convingeți juriul să nu vă ruleze sursa (Pascal sau C/C++), ci direct executabilul. Merge simțitor mai repede. Asta numai în cazul în care vă temeți că programul ar putea să nu se încadreze în timp.
  • Dacă se poate, evitați lucrul cu pointeri. Programele care îi folosesc sunt mai greu de depanat și se pot bloca mult mai ușor.
  • Să presupunem că aveți de lucrat cu matrice de dimensiuni maxim 100x100. Unii elevi au obiceiul să dimensioneze la început matricele de 5x5 sau 10x10, doarece sunt mai comod de evaluat cu „Evaluate” (Ctrl-F4) sau „Watch” (Ctrl-F7). Acest lucru este adevărat, dar există riscul ca la sfârșit să uitați să redimensionați matricele de 100x100. Decât să faceți o asemenea greșeală (care în mod sigur vă va compromite toată problema), mai bine setați dimensiunile corecte de la început. De altfel, ideal ar fi ca depanarea programelor să fie suprimată cu totul și programul să meargă din prima.
  • Evitați lucrul cu numere reale, dacă puteți. Operațiile în virgulă mobilă sunt mult mai lente. De exemplu, testul dacă un număr este prim nu va începe în nici un caz cu linia
while i<=Sqrt(N) do
ci cu linia
while i*i<=N do
Din punct de vedere logic, condițiile sunt perfect echivalente. Totuși, prima se evaluează de câteva zeci de ori mai încet decât a doua.
  • Dacă lucrați cu numere reale, nu folosiți testul
R1=R2
deoarece pot apărea erori, ci implementați o funcție:
function Equal(R1,R2:Real):Boolean;
begin
  Equal:=(Abs(R1-R2)<0.00001);
end;
Numărul de zerouri de după virgulă trebuie să fie suficient de mare astfel încât două numere diferite să nu fie tratate drept egale (se poate lucra de pildă cu 0.000001).
  • Tot în cazul numerelor reale, evitați pe cât posibil să faceți împărțiri, deoarece sunt foarte greoaie. De exemplu:
    • X/5 🡘 0.2*X
    • X/Y/Z 🡘 X/(Y*Z)
  • Optimizările de genul X shl 1 respectiv X<<1 în loc de 2*X sunt niște artificii de cele mai multe ori neesențiale, care în schimb fac formulele mai lungi, greu de urmărit și pot crea complicații. Cel mai bine este să lucrați cu notațiile obișnuite și doar la sfârșit, dacă timpul de rulare trebuie redus cu orice preț, să faceți înlocuirile.
  • Alegeți-vă numele de variabile în așa fel încât programul să fie clar. Sunt permise mai mult de două litere! Numele fiecărei proceduri, funcții, variabile trebuie să-i explice clar utilitatea. E drept, lungimea programului crește, dar codul devine mult mai limpede și timpul de depanare scade foarte mult. Ca o regulă generală, claritatea programelor face mult mai ușoară înțelegerea lor chiar și după o perioadă mai îndelungată de timp (luni, ani). Nu trebuie nici să cădeți în cealaltă extremă. De exemplu, nu depășiți 10 caractere pentru un nume de variabilă.
  • Salvați programul cât mai des. Dacă vă obișnuiți, chiar la fiecare două-trei linii. După ce o să vă intre în reflex n-o să vă mai incomodeze cu nimic acest obicei, mai ales că în ziua de azi salvarea unui program de 2-3 KB se face practic instantaneu. Au fost frecvente cazurile în care o pană de curent prindea pe picior greșit mulți concurenți, iar după aceea nu mai este absolut nimic de făcut, pentru că nimeni nu vă va crede pe cuvânt că ați făcut programul și că el mergea.
  • Obișnuiți-vă să programați modular. Faceți proceduri separate pentru citirea și inițializarea datelor, pentru sortare, pentru afișarea rezultatelor etc. În general nu se recomandă să scrieți proceduri în alte proceduri (adică e bine ca toate procedurile să aparțină direct de programul principal). Procedurile, acolo unde e posibil, nu trebuie să depășească un ecran, pentru a putea avea o viziune de ansamblu asupra fiecăreia în parte. Acest lucru ajută mult la depanare.
  • Rulați programul cât mai des. În primul rând după ce scrieți procedura de citire a datelor. Dacă e nevoie de sortarea datelor de intrare, nu strică să vă convingeți că programul sortează bine, rulând două-trei teste oarecare. E păcat să pierdeți puncte dintr-o greșeală copilărească.
  • O situație delicată apare când fișierul de intrare conține mai multe seturi de date (teste). În acest caz, atenția trebuie sporită, deoarece dacă la primul sau al doilea test programul vostru dă eroare și se oprește din execuție, veți pierde automat și toate celelalte teste care urmează. Dacă în fișierul de intrare exista un singur set de date, atunci pierderea din vedere a unui caz particular al problemei nu putea duce, în cel mai rău caz, decât la picarea unui test. Așa însă, picarea unui test poate atrage după sine picarea tuturor celor care îi urmează. Pe lângă corectitudinea strict necesară, programul trebuie să se încadreze și în timp pentru orice fel de test. Dacă la primul sau al doilea test din suită programul depășește timpul (sau, și mai rău, se blochează), e foarte probabil să fie oprit din execuție de către comisie, deci din nou veți pierde toate testele care au rămas neexecutate. Uneori comisia este binevoitoare și acceptă să modifice fișierul de date, tăind din el setul pe care programul vostru nu merge, dar acest lucru este greoi și nu tocmai cinstit față de ceilalți concurenți, deci nu vă bazați pe asta.
  • Tot în situația în care există mai multe seturi de date în fișierul de intrare, dacă ieșirea se face într-un fișier, este bine ca după afișarea rezultatului pentru fiecare test să actualizați fișierul de ieșire (fie prin comanda „Flush”, fie prin două proceduri, „Close” și „Append”). În felul acesta, chiar dacă la unul din teste programul se blochează sau dă eroare, rezultatele deja scrise rămân scrise. Altfel, e posibil ca rezultatele de la testele anterioare să rămână într-un buffer în memorie, fără a fi „vărsate” pe disc.
  • Dacă fișierul de ieșire are dimensiuni foarte mari, de exemplu dacă vi se cer toate soluțiile, iar numărul acestora este de ordinul zecilor de mii, puteți avea surpriza ca timpul să nu vă ajungă pentru a le tipări pe toate în fișierul de ieșire. Și în acest caz, este recomandat ca după tipărirea fiecărei soluții să executați comanda Flush, sau să închideți fișierul de ieșire și să-l redeschideți în modul Append.

J

Dacă ați trecut cu bine și de faza de scriere a programului, mai aveți doar părțile de depanare și testare, care de multe ori se îmbină. Metoda cea mai bună de depanare este următoarea:

Începeți cu un test nici prea simplu, nici prea complicat (și ușor de urmărit cu creionul pe hârtie) și executați-l de la cap la coadă. Dacă merge perfect, treceți la teste mai complexe (minim 4 teste și maxim 7-8). Dacă le trece și pe acestea, puteți fi mândri. Legile lui Murphy în programare se aplică în continuare: „Depanarea nu poate demonstra că un program merge; ea poate cel mult demonstra că un program nu merge”. Totuși, dacă programul vostru a mers perfect pe 7-8 teste date la întâmplare, există șanse foarte mari să meargă pe majoritatea testelor comisiei, sau chiar pe toate.

  • Exemplul dat în enunț nu are în general nici o semnificație deosebită (de fapt, are mai curând darul de a semăna confuzie printre concurenți), iar dacă programul merge pe acest test particular, nu înseamnă că o să meargă și pe alte teste. În culegere nu a fost explicat pe larg algoritmul decât pe exemplul din enunțul fiecărei probleme, dar aceasta s-a făcut numai pentru a nu supraîncărca materialul.
  • Dacă la unul din teste programul nu merge corespunzător, rulați din nou testul, dar de data aceasta procedură cu procedură. După fiecare procedură evaluați variabilele și vedeți dacă au valorile așteptate. În felul acesta puteți localiza cu precizie procedura, apoi linia unde se află eroarea. Corectați în această manieră toate erorile, până când testul este trecut.
  • În acest moment, luați de la capăt toate testele pe care programul le-a trecut deja. În urma depanării, s-ar putea ca alte greșeli să iasă la suprafață și programul să nu mai meargă pe vechile teste.
  • Repetați procedeul de mai sus până când toate testele merg. Dacă vă obișnuiți să programați modular și îngrijit, depanarea și testarea n-ar trebui să dureze mai mult de 5-10 minute. Din acest moment, nu mai modificați nici măcar o literă în program, sau dacă țineți să o faceți, păstrați-vă în prealabil o copie. Nu vă bazați pe faptul că puteți să țineți minte modificările făcute și să refaceți oricând forma inițială a programului în caz că noua versiune nu va fi bună.
  • Dacă totuși nu-i puteți „da de cap” programului, iar timpul alocat problemei respective expiră, aduceți programul la o formă în care să meargă măcar pe o parte din teste (pe jumătate, de exemplu) și treceți la problema următoare.

K

  Dec(Nr_probleme_nerezolvate);
end; { while }


Probabil nu veți fi de acord cu toate sfaturile date mai sus. E bine însă să le aplicați. Scopul pentru care ele au fost incluse în această carte este de a ajuta concurenții să se acomodeze mai ușor cu atmosfera concursului. De multe ori, primul an de participare la olimpiadă se soldează cu un rezultat cel mult mediu, deoarece, oricât ar spune cineva „ei, nu-i așa mare lucru să mergi la un concurs”, experiența acumulată contează mult. De aceea, abia de la a doua participare și uneori chiar de mai târziu încep să apară rezultatele. Intenția autorului a fost să vă ușureze misiunea și să vă dezvăluie câteva din dificultățile de toate felurile care apar la orice concurs, pentru a nu vă da ocazia să le descoperiți pe propria piele. Poate că aceste ponturi vă vor fi de folos.