ŠIFRA DRŽAVNO TAKMIČENJE III razred UKUPAN BROJ OSVOJENIH BODOVA Test pregledala/pregledao...... Podgorica,... 2009. godine
Uputstva takmičarima Ovo takmičenje sastoji se od rješavanja 3 problemska zadatka u vremenu od 3 sata (180 minuta). Zadatke je potrebno rješavati u jednom od sljedećih programskih jezika: Pascal, C, C++ ili Java. Takmičari koji koriste Pascal moraju programirati u programskom alatu FreePascal ili TurboPascal. Takmičari u C-u i C++-u moraju koristiti programske alate DJGPP, DevCpp ili GCC. Za programski jezik Java predviđena je upotreba platfome Eclipse. Dozvoljeno je koristiti editor po izboru te pomoću navedenih alata prevoditi izvorni kod u izvršnu datoteku. Za početak, provjerite da li ste dobili tačno 7 stranica sa tekstom (uključujući i ovu koju trenutno čitate i naslovnu stranicu). Morate imati dvije stranice s uputstvima (ovu i još jednu), jednu uvodnu stranicu s tabelom zadataka i još 3 stranice sa tekstovima zadataka. Tokom takmičenja ne smijete komunicirati ni sa jednom osobom, osim dežurne osobe takmičenja. To znači da morate raditi samostalno i ne smijete koristiti Internet. Takođe, zabranjena je upotreba bilo kakvih ranije napisanih programa ili dijelova programa. Po isteku vremena predviđenog za takmičenje, na desktopu u folderu sa imenom Takmicenje2009 moraju se nalaziti datoteke sa snimljenim izvornim kôdovima rješenja. Nakon takmičenja, komisija će testirati vaša rješenja na ranije izabranim test podacima i dodijeliti vam određeni broj bodova. Na kraju svakog zadatka dati su primjeri test podataka. Ti primjeri služe da bi vam tekst zadataka bio što je moguće jasniji te za provjeru formata ulaza i izlaza, a ne služe za provjeru ispravnosti vašeg programa. Ako vaš program radi na tim primjerima, to nije garancija da će raditi na službenim podacima za testiranje. Zadaci ne nose jednak broj bodova. Lakše i brže rješivi zadaci nose manje bodova, dok teži nose više bodova. Svaki test podatak u nekom zadatku nosi jednak broj bodova. Ukupni broj bodova na nekom zadatku jednak je zbiru bodova test podataka koji se poklapaju sa službenim rješenjem. Ukupan broj bodova jednak je zbiru bodova na svim zadacima. Primjetite da svi zadaci imaju ulaz iz datoteke i izlaz u datoteku. Sve informacije o zadacima (ime zadatka, ulaz, izlaz, vremensko i memorijsko ograničenje, način bodovanja) možete naći na uvodnoj stranici s naslovom Zadaci. Ako vam nije jasno nešto u vezi načina organizacije ovog takmičenja, odmah postavite pitanje dežurnom da vam to razjasni. Tokom cijelog takmičenja možete postavljati pitanja dežurnom u vezi zadataka. Dozvoljena su pitanja koja razjašnjavaju nejasnoće u tekstu zadatka. Ne smijete postavljati pitanja u vezi rješavanja zadataka. Prije nego postavite pitanje, pročitajte još jednom zadatak, jer je moguće da ste u prethodnom čitanju preskočili dio teksta zadatka.
VAŽNO za C/C++! Glavni program (glavna funkcija) mora biti deklarisan kao: int main(void) { }. Program mora završiti svoje izvođenje naredbom return 0; unutar funkcije main ili naredbom exit(0);. Zabranjeno je koristiti biblioteke <conio.h> i <cconio>, kao i sve funkcije deklarisane u ovim bibliotekama (npr. clrscr(); getch(); getche(); i sl.). Zabranjeno je koristiti i sve sistemske (nestandardne) biblioteke. Zabranjeno je koristiti funkcije itoa() i ltoa() jer one ne postoje u standardu jezika C/C++. Umjesto tih funkcija možete koristiti funkciju sprintf() deklarisanu u <stdio.h> i <cstdio>., koja ima i veće mogućnosti primjene, Dozvoljeno je koristiti sve ostale standardne biblioteke (koje su dio jezika), uključujući i STL (Standard Template Library) u jeziku C++. VAŽNO za Pascal! Program mora regularno završiti svoje izvođenje naredbom end. unutar glavnog programa ili naredbom halt;. Zabranjeno je koristiti bilo kakve biblioteke, a posebno biblioteku crt, tj. zabranjeno je u programu imati direktivu uses. To znači da u programu ne smije biti naredbi clrscr() i readkey(). Nepoštovanje ovih pravila ili nepridržavanjem formata izlaznih podataka rezultiraće nepovratnim gubitkom bodova. Nemojte štampati ništa što se u zadatku ne traži, kao npr. poruke tipa Rjesenje je: ili Unesite brojeve i slično! Srećno i uspješno takmičenje!
Zadatak Zadatak1 Zadatak3 Zadatak3 zadatak1.java zadatak2.java zadatak3.java Izvorni kôd zadatak1.pas zadatak2.pas zadatak3.pas zadatak1.c zadatak2.c zadatak3.c zadatak1.cpp zadatak2.cpp zadatak3.cpp Ulazna datoteka zad1.txt zad2.txt zad3.txt Izlazna datoteka rez1.txt rez2.txt rez3.txt Memorijsko ograničenje (heap) Memorijsko ograničenje (stack) Vremensko ograničenje (po test podatku) 32 MB 32 MB 32 MB 8 MB 8 MB 8 MB 3 sekunde 3 sekunde 5 sekundi Broj test podataka 5 5 5 Broj bodova (po test podatku) 5 7 8 Ukupno bodova 25 35 40 Napomena: Vremensko ograničenje mjereno je na računaru baziranom na dva procesora AMD Athlon MP 2600+ i operativnim sistemom Linux. Program u C-u i C++-u treba kompajlirati sa sljedećim opcijama: O2 lm static, a program u Pascalu sa O1 XS.
Zadatak 1 Putanja automobila opisuje se koordinatama tjemena izlomljene poligonalne linije. Automobil započinje kretanje iz prve tačke izlomljene linije i nastavlja kretanje sve dok ne dođe do posljednje tačke. Bilo koja tri uzastopna tjemena poligonalne linije ne leže na istoj pravoj. Ana pokušava da odredi koliko ima lijevih krivina na putu. Pomozite Ani da napiše program koji će izračunati broj lijevih krivina. Ulazni podaci Ulazna datoteka u prvom redu sadrži samo jedan prirodan broj N (1 N 1000) koji označava broj duži koji čine izlomljenu liniju. U sljedećih N+1 redova nalaze se po dva broja koja redom predstavljaju koordinate tjemena izlomljene linije. Izlazni podaci U izlaznoj datoteci štampati jedan broj koji je rješenje zadatka. Primjeri test podataka ulaz 4 1 1 2 2 3 2 3 3 2 3 izlaz 2 Rješenje Najjednostavniji način je upotreba vektorskog proizvoda dva vektora, gdje za vektore uzimamo uzastopne orijentisane duži izlomljene linije. Moguće je i kroz svaka dva uzastopna tjemena povući pravu pa provjeravati sa koje se strane te prave nalazi sljedeće tjeme. Ako je vektor AB zadat tjemenima A(ax, ay) i B(bx,by) a tačka P(px,py) tada je dovoljno odrediti znak izraza (bx-ax)*(py-ay)-(by-ay)*(px-ax).
Zadatak 2 Nastavnica matematika Mira otkrila je zanimljiv način da pomogne učenicima da nauče pretvaranje brojeva iz dekadnog brojnog sistema u binarni brojni sistem i obrnuto. Naime, ona zamisli jedan broj u sistemu sa osnovom 10, a učenici odrede njegov binarni zapis tako da je prva cifra u binarnom zapisu 1. Na primjer, tako se broj 1910 prevodi u binarni broj 100112 (jer je 19 = 1 2 4 +0 2 3 +0 2 2 +1 2 1 +1 2 0 ) a broj 29 10 prevodi se u binarni broj 11101 2 (jer je 29 = 1 2 4 +1 2 3 +1 2 2 +0 2 1 +1 2 0 ). Zatim na tako dobijeni binarni broj učenici primjenjuju operaciju kružnog pomjeranja udesno: posljednja cifra (tj. krajnja desna cifra) postaje prva cifra, a sve ostale cifre pomjeraju se za po jednu poziciju udesno. Učenici svaki put zapisuju dobijeni binarni broj. Marko je prvi uočio jednu zanimljivost: bez obzira koji je polazni broj, poslije određenog broja koraka ponovo se dobija polazni broj. Na primjer, za broj 1910 = 100112 imamo: 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 1 1 Nastavnica Mira traži od učenika da odrede koji je od dobijenih brojeva najveći i da odrede njegov dekadni zapis. U navedenom primjeru, najveći je broj 111002 (broj u trećem redu) a njegov dekadni zapis je: 1 2 4 +1 2 3 +1 2 2 +0 2 1 +0 2 0 = 28 10. Marko je dobar programer pa je odlučio da napiše program koji će umjesto njega izračunati traženi broj. Ulazni podaci Ulazna datoteka sadrži samo jedan prirodan broj N (1 N 32767). Izlazni podaci U izlaznoj datoteci štampati jedan broj koji je rješenje zadatka. Primjeri test podataka ulaz 19 izlaz 28 ulaz 15 izlaz 15 ulaz 37 izlaz 50 Napomena: Binarni zapis broja N (1 N 32767) može imati najviše 15 cifara.
Rješenje Ovo je direktno rješenje gdje se broj prevodi u binarni i izračunava se njegov dekadni ekvivalent pa se zatim određuje onaj koji je najveći. Može se koristiti i bit po bit pomjeranje SHR pa tada nije potrebno prevoditi broj u binarni. Izračunavaju se cifre binarnog broja a ne sam broj. Program zad2; Var I,J,Max,Num,NumDigits,Digit:Integer; Digits: Array[1..20] Of Integer; Begin Max := Num; NumDigits := 0; While Num > 0 Do Begin Inc(NumDigits); Digits[NumDigits] := Num Mod 2; Num := Num Div 2 End; For I:=1 To NumDigits - 1 Do Begin Digit := Digits[1]; For J := 2 To NumDigits Do Digits[J-1] := Digits[J]; Digits[NumDigits] := Digit; Num := 0; For J := NumDigits DownTo 1 Do Num := Num*2 + Digits[J]; If Num > Max Then Max := Num End; End;
Zadatak 3 Menadžer jedne velike prodavnice odlučio je da na velikom panou emituje reklamni spot za novi proizvod. Da bi napravili optimalan raspored emitovanja spota, radnici prodavnice su u toku jednog dana zapisivali vremena kada je kupac ušao u prodavnicu i kada je izašao iz prodavnice. Menadžer je pretpostavio da će raspored dolazaka i odlazaka kupaca biti takav i sljedećeg dana. On hoće da napravi raspored emitovanja spotova tako da svaki kupac u toku svog boravka u prodavnici vidi ili čuje spot najmanje dva puta. Takođe, radnicima može dosaditi da slušaju istu reklamu cio dan, pa menadžer zahtijeva da broj emitovanja spota u toku dana bude najmanji mogući. Aida i Matija su programeri u kompaniji koja je vlasnik prodavnice. Pomozite im da napišu program koji će napraviti traženi rapored emitovanja reklamnog spota. Početak emitovanja reklame je u cjelobrojnom trenutku vremena. Svako emitovanje spota završava se prije početka sljedećeg vremenskog intervala. Ako reklama počinje da se emituje u trenutku kada kupac ulazi u prodavnicu ili izlazi iz nje, tada se smatra da je uspio vidjeti ili čuti tu reklamu. Ulazni podaci U prvom redu ulazne datoteke upisan je prirodan broj N (1 N 3000) broj kupaca koji su posjetili prodavnicu za jedan dan. U sljedećih N redova upisani su parovi brojeva A i, B i koji predstavljaju redom vremena dolaska i napuštanja prodavnice (0< A i < B i <10 6 ) Izlazni podaci U prvom redu izlazne datoteke štampati broj emitovanja spota za jedan dan. U sljedećim redovima štampati trenutke vremena u rastućem redosljedu kada treba emitovati reklamni spot. Ako postoji više rješenja, štampati samo jedno od njih. Primjeri test podataka ulaz 5 1 10 10 12 1 10 1 10 23 24 Izlaz 5 5 10 12 23 24 Ulazni podaci mogu se prikazati na sljedećoj slici:
Svi kupci koji su ušli u 1 a izašli u 10 (ima ih tri), vidjeli su reklame koje su počele u 5 i u10. Kupac koji je ušao u 10 i izašao u 12 vidio je dvije reklame (one koje počinju u 10 i u 12) a kupac koji je ušao u 23 vidio je dvije reklame (one koje počinju u 23 i u 24). Rješenje Zadatak se može preformulisti na sljedeći način: na brojnoj osi rasporediti najmanji mogući broj cjelobrojnih tačaka tako da u svakom intervalu budu dvije tačke. Koristićemo sljedeće strukture: const type var MaxN=3000; Infinity=MaxLongInt; TSegment = record left, right : longint; end; n : longint; {brojj intervala } segment : array [1..MaxN] Of TSegment; {intervali} point : array [1..MaxN*2] Of longint; {tacke koje postavljamo} Sortirajmo intervale u rastućem redosljedu po desnoj granici, a ako su desne granice jednake tada po lijevoj granici u opadajućem poretku (nije napisan kod za ovaj dio programa). Sada provjeravamo redom intervale i određujemo koliko tačaka treba staviti u interval. Ako trebamo staviti dvije tačke (uslov if last < left), postavljamo ih da budu krajnje desne tačke u intervalu (kod: PrevLast := right-1; Last := right;). Ako treba postaviti samo jos jednu tacku (if PrevLast < left) tada postavljamo da je PrevLast := Last; Last := right. procedure solve; var Last, PrevLast : longint; {dvije posljednje postavljene tacke } i : longint; begin res := 0; {broj postavljenih tacaka} Last := -Infinity; PrevLast := -Infinity; for i := 1 to N do with segment[i] do if last < left then { treba postaviti jos dvije tacke} begin inc(res);
point[res] := right-1; inc(res); point[res] := right; PrevLast := right-1; Last := right; end else if PrevLast < left then { treba postaviti jos jednu tacku} begin inc(res); point[res] := right; PrevLast := Last; Last := right; end; end; {Procedure solve}