Din GInfo nr. 2

Soluțiile problemelor propuse

După ce ne-am ocupat de problemele date la Olimpiada Națională de Informatică, a venit rândul problemelor propuse în Gazeta de Informatică nr. 2 (martie 1998)

P029801: Ogor

Configurația ogorului se reține în matricea b, care va fi parcursă de sus în jos, de la stânga la dreapta. La întâlnirea unui tip de plantă (în poziția (i,j)) se determină cea mai mare suprafață de teren drepunghiulară ce are colțul din stânga sus în poziția (i,j) și conține numai un singur fel de plantă (procedura numaratoare).

Odată determinat dreptunghiul, acesta se "elimină" (elementelor lui li se atribuie valoarea șirului de caractere vid: '' ), iar operațiile de determinare se continuă în restul matricei.

Listing OGOR.PAS

P029802: Grăniceri

La fiecare pas se citesc din cele N (N<=g) fișiere de intrare câte o înregistrare (care constă în tripletul (zi, ('IN' sau 'OU'), nume).

Despre aceste persoane spunem că trec granița la momentul actual, iar informația despre ele o reținem în vectorul trece. Informația despre toate persoanele care au trecut granița până în ziua actuală (deci care în fișiere se găsesc înainte de înregistrarea curentă) sunt reținute în vectorul trecut. În câmpul sens al acestei variabile se reține sensul ultimei deplasări ('IN' sau 'OU'). Variabila buc contorizează persoanele care au trecut granița fie 'IN' fie 'OU'.

Reamintim că la fiecare pas se citește câte o înregistrare din fișierele de intrare. Pentru fiecare astfel de înregistrare se testează dacă persoana care a făcut deplasarea se află sau nu în vectorul trecut (procedura caut_data_prec). Da-că se află în acest vector atunci se compară sensul depla-sării actuale cu sensul ultimei deplasări. Dacă ele coincid înseamnă că persoana respectivă a trecut cel puțin o dată granița ilegal.

La sfârșit, după ce au fost epuizate toate fișierele de in-trare, se testează care dintre persoane au sensul ultimei de-plasări 'OU', acestea fiind scrise în fișierul 'AFARA.OUT'.

Listing GRANICER.PAS

P029803: Camping

Să analizăm în primul rând cazul în care avem o singură căsuță. Problema ar fi echivalentă cu determinarea numărului maxim de segmente dispuse pe o aceeași dreaptă și care nu se intersectează. O primă idee de rezolvare a acestei probleme ar fi metoda programării dinamice și anume în modul descris la problema "Închirieri auto".

Totuși, datorită faptului că segmentele au lungimi egale, maximul numărului solicitărilor începând cu ziua solicit[i] este dat de segmentul cel mai apropiat de cel curent și care nu se intersectează cu acesta. De aceea nu mai este nevoie de metoda programării dinamice, fiind suficient un algoritm Greedy: pentru fiecare zi a anului începând cu prima, determinăm dacă există o solicitare care începe cu acea zi. Dacă da și dacă această căsuță este liberă, satisfacem solicitarea.

În cazul nostru, având k căsuțe, aplicăm acest algoritm pentru fiecare căsuță în parte, verificând ca nici unul dintre turiști să nu fie cazat în două căsuțe.

Listing CAMPING.PAS

P029804: Expediție pe Marte

Aplicăm metoda programării dinamice. Pentru fiecare po-ziție din matrice determinăm dacă se poate ajunge în ea pornind din colțul stânga sus și executând mișcări doar în jos și spre dreapta reținute în matricea e11. Un element al matricei are valoarea true dacă la el poate ajunge un robot care pleacă din colțul stânga sus, false în caz con trar.

Deoarece un robot care întâlnește o stâncă este blocat într-o direcție, este necesar să determinăm din nou pentru fiecare element al matricei dacă se poate ajunge în el plecând din colțul dreapta jos executând mișcări în sus și la stânga. e11[i,j]=emn[i,j]=true înseamnă că poziția (i,j) poate fi vizitată de un robot care pleacă din poziția (1,1) și ajunge în poziția (m,n). Modul de calcul al elementelor matricei e11 este următorul: e11[1,1]=true, deoarece roboții pleacă din această poziție; pentru prima linie și prima coloană avem true până la întâlnirea primei stânci, false în rest. Pentru orice altă poziție vom avea e11[i,j]=true dacă nu există stâncă și dacă cel puțin una din pozițiile e11[i-1,j] sau e11[i,j-1] este true.

Listing MARTE.PAS

P029805: Hotel

Problema, ca grad de dificultate este cea mai simplă dintre aceste probleme propuse, în schimb numărul de linii de cod sursă este cel mai mare în comparație cu cel al celorlalte probleme.

Înformațiile despre bucătari și cofetari sunt stocate în doi vectori denumiți sugestiv bucatar și cofetar, fiecare element al acestor doi vectori fiind o structură de tip înregistra-re, având câmpurile: niv, varsta, nume. După ce elementele vectorilor sunt completate cu date din fișierele de intrare corespunzătoare, se trece la analiza întrebărilor. Acestea sunt citite pe rând din fișierul de intrare intreb.in. Fiecare întrebare este prelucrată cu ajutorul procedurii desface și este desfăcută în părțile ei componente și anume: tipul solicitat al unui potențial angajat (variabila ce va lua valoarea 1 pentru bucatar, 2 pentru cofetar, 3 pentru orice), relația (variabila relatie va lua valoarea 1 pentru <, 2 pentru >, 3 pentru =, 4 pentru <=, 5 pentru >=), numărul N din enunț (în program variabila nivel) și o variabilă booleană minmax care va lua valoarea true dacă în câmpul zzzz (din enunț) este MIN, false în caz contrar. Aceste informații fiind determinate se caută (cu procedura cauta) în "baza de date" persoana solicitată. În urma executării procedurii, în cazul unei căutări cu succes, în variabila booleană exista vom avea true, iar numărul întreg s va indica poziția în vectorul cu datele de intrare (bucatar sau cofetar) al înregistrării care satisface condiția din întrebare.

Listing HOTEL.PAS

P029806: Radar

Sesizările rachetelor sunt citite într-o structură având câmpurile: timp, li (linie) și co (coloană). Pentru fiecare astfel de sesizare se va determina dacă mai există încă două astfel de sesizări care respectă coliniaritatea și viteza cu prima. Dacă sunt determinate, iar baza ar putea fi atinsă de rachetă (funcția atinge_sol), soldații vor fi alertați (procedura alerteaza). După aceea, pentru a nu se face alertări suplimentare, racheta va fi eliminată din vectorul cu sesizările (sesiseaza) prin modificarea valorii câmpului timp la 0.

Listing RADAR.PAS

P029807: Închirieri auto

Datele de intrare le citim în vectorul solicit care reține fiecare solicitare a unui autoturism sub forma unei perechi (a,b), unde a reprezintă începutul perioadei de închiriere, iar b reprezintă sfârșitul acelei perioade. Rezolvăm problema prin metoda programării dinamice. Construim un vector f cu 365 de elemente, în care pe poziția i reținem numărul maxim de zile (cu număr de ordine mai mic decât i) în care a fost închiriat autoturismul. Modul de calcul al e-lementelor lui f este următorul: f[0]=0. Apoi

f[i]=max{ f[solicit[j].a-1]+solicit[j].

b - solicit[j].a/solicit[j].b<=i }

Semnificația acestei formule este următoarea: dintre toate solicitările care au ziua de expirare înaintea zilei curente (i), o alegem pe aceea (să fie aceasta j) pentru care suma dintre perioada de închiriere și numărul maxim de zile în care este închiriată mașina înaintea datei de începere a închirierii j, să fie maxim.

Listing AUTO.PAS

P029808: Robot

Observăm că sunt suficienți n roboți pentru a culege toate piesele. (Această afirmație am dedus-o din faptul că un robot poate culege piesele de pe o coloană întreagă (și nu numai) deci deoarece matricea are n coloane, sunt suficienți n roboți. Pentru a determina numărul minim de roboți observăm că un robot trebuie să ajungă neapărat pe ultima linie și în plus într-o soluție optimă doi roboți nu ajung în aceeași căsuță de pe ultima linie (coborând de sus în jos). Deci numărul minim de roboți va fi egal cu numărul minim de coloane în ale căror cele mai de jos poziții vor ajunge roboții.

Vom pleca cu câte un robot din ultima (cea mai de jos) căsuță a fiecărei coloane și vom parcurge matricea în sus și la stânga încercând de fiecare dată să eliminăm un număr maxim de piese (elemente având valoarea 1 în matrice). Dacă un robot nu culege nici o piesă, înseamnă că acest robot nefiind util, nu face parte din numărul minim necesar.

Listing ROBOT.PAS

P029809: Compilator

Se construiește un vector (numit mem) având dimensiunea de 1024 byte, care reprezintă porțiunea de memorie a compilatorului nostru. Completarea locațiilor de memorie se putea face într-o singură etapă, dacă nu ar fi fost ultimele două tipuri de instrucțiuni. În situația dată sunt necesare două etape. În prima etapă completăm șirul cu rezultatul instrucțiunilor de tip 1, 2 și 3, iar pentru instrucțiunile de tip 4 și 5 rezervăm doar octeții necesari (2 pentru instrucțiunea 4 și 1 pentru instrucțiunea 5). La cea de a doua parcurgere vom completa și locațiile astfel rezervate.

Instrucțiunile de tip 4 și 5 necesită reținerea tuturor etichetelor programului (vectorul et), iar apoi completarea vectorulului mem se realizează în felul următor:

  • dacă instrucțiunea curentă este de tipul 4 determinăm poziția în memorie (în vectorul mem) de la care încep instrucțiunile precedate de eticheta dintre < > și scriem rezultatul obținut în vector conform specificației instrucțiunii;
  • dacă instrucțiunea este de tipul 5, atunci determinăm poziția din memorie de la care încep instrucțiunile atașate etichetei dintre [ ], și scriem în locul rezervat rezultatului instrucțiunii curente conținutul locației de me-morie a cărei poziție am determinat-o.

Listing COMPILAT.PAS

[cuprins]