PilsProg 2024

Výsledky Lite

#JménoPříjmeníSplněných úlohČas
1MatyášVítek910,227
2LukášPatejdl943,213
3PetrZaoral9317,119
4JanBrichcín9356,246
5ŠtefanProkop9652,246
6DavidJanovský7155,529
7DavidMacner673,041
8MichalŠpelina6579,748
9JakubPulinger5376,968
10FilipFischer3134,890
11JakubKašák1142,755
12KristiánMaas1143,967

Cena udělená za 1. místo v PilsProg Lite: Externí 2TB 2.5" HDD

Výsledky kvalifikace

#JménoPříjmeníSplněných úlohČasFinále
1JáchymKouba649,718Postupuje do finále
2MatyášVítek6832,402Postupuje do finále
3Hlib Arseniuk5283,896Postupuje do finále
4Anna-KristinaMigel5547,544Postupuje do finále
5PetrStarý52 252,759Postupuje do finále
6ErikJežek55 017,888Postupuje do finále
7MatyášDavid4186,949Postupuje do finále
8JanBrichcín4243,128Postupuje do finále
9DavidMacner4264,787Postupuje do finále
10MichalŠpelina42 889,613Postupuje do finále
11LucianPoljak44 742,560Postupuje do finále
12PetrZaoral3160,344Postupuje do finále
13OndřejBartoš3446,892Postupuje do finále
14JakubSvítek3705,708Postupuje do finále
15LukášPatejdl14,239-
16TomášZlámal17,687-
17ŠtefanProkop192,430-
18ŠtěpánKuch198,959-
19AlexandrVituško1170,497-
20JakubUrban1188,267-
21VáclavZach1485,002-

Výsledky finále

#JménoPříjmeníSplněných úlohČas
1JáchymKouba36,128
2MatyášVítek21,347
3JakubSvítek21,799
4ErikJežek22,018
5Anna-KristinaMigel22,227
6PetrZaoral22,450
7OndřejBartoš22,963
8JanBrichcín23,342
9LucianPoljak23,412
10PetrStarý24,109
11MatyášDavid11,260
12DavidMacner12,684
13MichalŠpelina00,000
14Hlib Arseniuk00,000

Vysvětlivky: Čas vyřešení je počítán v hodinách od zveřejnění úlohy.

Ilustrační úlohy

NázevČísloÚspěšných řešitelů
AxB170139
AplusB170234
Největší ze tří celých čísel170331
Pascalův trojúhelník170418

Lite1 úlohy

NázevČísloÚspěšných řešitelů
Malá násobilka24117
Meziměna24126
Řazení hvězdiček24137

Lite2 úlohy

NázevČísloÚspěšných řešitelů
Délka filmu24149
Histogram24159
Zrcadlová matice24169

Lite3 úlohy

NázevČísloÚspěšných řešitelů
Filtr hodnot24179
Index minima24189
Symetrická matice24199

Kvalifikační úlohy

NázevČísloÚspěšných řešitelů
Pálivá sklizeň24218
Stupnice pálivosti242221
Výběrové zemědělství24234
Výroba omáček242410
Zalévání papriček242512
Zeď proti škůdcům242613

Finálové úlohy

NázevČísloÚspěšných řešitelů
Kivule berou243110
Líný cyklista24321
Okresní silnice24330
Poštovní pevnost243412
Schodiště24350

A jaké bylo finále?

Finále začíná ...

Harmonogram PilsProg 2024

Lite úlohy - řešení

Nejprve je stručně popsán způsob, jakým je možno úlohu řešit. Jak úlohy řešili soutěžící, je ukázáno na vybraných příkladech zdrojových kódů odevzdaných soutěžních úloh.

Malá násobilka

  1. Načíst číslo, pro které má být malá násobilka vypsána.
  2. V cyklu se známým počtem opakování vypisovat jednotlivé řádky. Jako druhý činitel použít řídící proměnnou.
  3. Je třeba dát si pozor na odsazení součinu, obzvláště pro číslo 10, kdy je rozdíl až o dvě místa.

Příklad zdrojového kódu:

program U2411MalaNasobilka; var n, i, d: Byte; begin ReadLn(n); if n=10 then d:=3 else d:=2; for i:=0 to 10 do WriteLn(i:2, ' x ', n, ' = ', i*n:d); ReadLn; end.

Meziměna

  1. Načíst počet testovacích případů.
  2. Pro každý testovací případ si načíst částku v původní měně, kurz nákupu původní měny a kurz prodeje cílové měny.
  3. Částku vynásobit kurzem nákupu a vydělit kurzem prodeje.
  4. Vypsat výslednou částku zaokrouhlenou na dvě desetinná místa.

Příklad zdrojového kódu:

import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int count = in.nextInt(); for (int i = 0; i < count; i++) { double first = in.nextDouble(); double second = in.nextDouble(); double third = in.nextDouble(); double result = Math.round(first * second / third * 100) / 100.0; System.out.println(result); } } }

Řazení hvězdiček

  1. Načíst počet hvězdičkových hodnocení a následně jednotlivá hodnocení jako řetěce (řádky) do pole řetězců.
  2. Seřadit pole libovolným řadícím algoritmem podle délky řetězců (hvězdičkových hodnocení).
  3. Vypsat seřazené pole, každé hvězdičkové hodnocení na samostatnou řádku.

Příklad zdrojového kódu:

#include <iostream> #include <map> using namespace std; int main(){ int n; string s; cin>>n; map<string, int> m; m["*"]=0; m["**"]=0; m["***"]=0; m["****"]=0; m["*****"]=0; for (int i=0;i<n;i++){ cin>>s; m[s]=m[s]+1; } for (auto it = m.rbegin(); it != m.rend(); it++) { for (int j = 0; j < it->second; j++) { cout << it->first << endl; } } return 0; }

Délka filmu

  1. Načíst počet testovacích případů.
  2. Pro každý testovací případ si načíst oba časy a rozdělit je na hodiny a minuty.
  3. Oba časy převést na minuty.
  4. Pokud je počáteční čas v minutách větší než koncový čas v minutách, přičíst ke koncovému času 24 hodiny v minutách (1440 minut).
  5. Odečíst počáteční čas od koncového a výsledek převést na hodiny a minuty.
  6. Vypsat délku filmu v hodinách a minutách v požadovaném formátu (pozor na počáteční nuly).

Příklad zdrojového kódu:

#include <iostream> #include <string> int mins(const std::string &time) { return std::stoi(time.substr(0, 2)) * 60 + std::stoi(time.substr(3, 2)); } void mins2(int minuty, int &h, int &min) { h = minuty / 60; min = minuty % 60; } int main() { int iters{}; std::cin >> iters; for (int i{}; i < iters; ++i) { std::string start, end; std::cin >> start >> end; int startMin = mins(start); int endMin = mins(end); int delka = (endMin >= startMin) ? endMin - startMin : endMin + 1440 - startMin; int hodinyFilm, minFilm{}; mins2(delka, hodinyFilm, minFilm); std::cout << (hodinyFilm < 10 ? "0" : "") << hodinyFilm << ":" << (minFilm < 10 ? "0" : "") << minFilm << std::endl; } return 0; }

Histogram

  1. Načíst počet hodnot histogramu a následně jednotlivé hodnoty např. do pole.
  2. Při načítání si určit maximální hodnotu, která udává výšku histogramu (tj. počet řádek).
  3. Vytvořit si dvourozměrné pole znaků sloužící jako plátno pro vykreslení histogramu bez omezení standardního výstupu (kde je výpis možný pouze po řádkách).
  4. Dle jednotlivých hodnot vykreslit do histogramu jednotlivé sloupce.
  5. Vypsat plátno na standardní výstup po řádkách.

Příklad zdrojového kódu:

program U2415Histogram; var count, x, y, max: Byte; h: Array of Byte; begin ReadLn(count); SetLength(h, count); max:=0; for x:=1 to count do begin Read(h[x]); if h[x]>max then max:=h[x]; end; ReadLn; for y:=max downto 1 do begin for x:=1 to count do begin if h[x]>=y then Write('| ') else Write('. '); end; WriteLn; end; ReadLn; end.

Zrcadlová matice

  1. Načíst řád matice.
  2. Vypisovat nuly jako jednotlivé prvky matice mimo vedlejší diagonálu po řádkách (např. pomocí dvou vnořených cyklů se známým počtem opakování).
  3. Vypisovat jedničky, pokud se prvek dle indexů nachází na vedlejší diagonále.

Příklad zdrojového kódu:

program JednotkovaMatice; var r, i, j: integer; begin readln(r); for i := 1 to r do begin for j := 1 to r do begin if j = r - i + 1 then write('1 ') else write('0 '); end; writeln; end; end.

Filtr hodnot

  1. Načíst počet testovacích případů.
  2. Pro každý testovací případ si načíst počet prvků posloupnosti, dolní a horní mez a následně načítat jednotlivé prvky.
  3. Pro každý prvek ověřit, zda je v otevřeném intervalu daném dolní a horní mezí. Pokud ano, prvek vypsat (všechny do jedné řádky oddělené mezerou).
  4. U prvního vypisovaného prvku dát pozor, aby před ním nebyla vypsána mezera.
  5. Po vypsání posledního prvku odřádkovat.

Příklad zdrojového kódu:

package me.prokop.pilsprog.lite3.filtr; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner s = new Scanner(System.in); int inputs; inputs = s.nextInt(); List<Integer> nums = new ArrayList<>(); for (int i = 0; i < inputs; i++) { s.nextLine(); nums.clear(); int inputNums = s.nextInt(); int min = s.nextInt(); int max = s.nextInt(); for (int j = 0; j < inputNums; j++) { int n = s.nextInt(); if (n > min && n < max) { nums.add(n); } } System.out.println(nums.toString().replace("[", "").replace("]", "").replace(",", "")); } } }

Index minima

  1. Načíst počet testovacích případů.
  2. Pro každý testovací případ si načíst počet hodnot a následně načítat jednotlivé hodnoty.
  3. U každé hodnoty ověřit, jestli se nejedná o aktuální minimum. Pokud ano, zaznamenat si hodnotu jako aktuální minimum a její index.
  4. Po ověření všech čísel vypsat uložený index minima.

Příklad zdrojového kódu:

#include <iostream> using namespace std; int main() { int t{}; int p{}; int nc{}; cin >> t; for (int i{}; i < t; i++) { cin >> p; int x = 0; int cisla[p]; for (int ii{}; ii < p; ii++) { cin >> cisla[ii]; } nc = cisla[0]; for (int s = 1; s < p; s++) { if (cisla[s] < nc) { nc = cisla[s]; x = s; } } cout << x << endl; } return 0; }

Symetrická matice

  1. Načíst počet testovacích případů.
  2. Pro každý testovací případ si načíst řád matice a následně její jednotlivé prvky do dvourozměrného pole.
  3. Projít prvky pod hlavní diagonálou a porovnávat je s odpovídajícímí prvky nad hlavní diagonálou.
  4. Pokud je nalezen rozdíl, porovnávání předčasně ukončit a vypsat „ne“. Pokud žádný rozdíl nalezen není, vypsat „ano“.

Příklad zdrojového kódu:

package me.prokop.pilsprog.lite3.symmat; import java.util.Scanner; public class Main { public static boolean validate(int[][] m, int r) { for (int y = 0; y < r; y++) { for (int x = 0; x < r; x++) { if (m[y][x] != m[x][y]) { return false; } } } return true; } public static void main(String[] args) { Scanner s = new Scanner(System.in); int testCases = s.nextInt(); s.nextLine(); for (int i = 0; i < testCases; i++) { int matSize = s.nextInt(); int mat[][] = new int[matSize][matSize]; for (int j = 0; j < matSize; j++) { s.nextLine(); for (int k = 0; k < matSize; k++) { mat[k][j] = s.nextInt(); } } System.out.println(validate(mat, matSize) ? "ano" : "ne"); } } }

Kvalifikační úlohy - řešení

Nejprve je stručně popsán způsob, jakým je možno úlohu řešit. Jak úlohy řešili soutěžící, je ukázáno na vybraných příkladech zdrojových kódů odevzdaných soutěžních úloh.

Pálivá sklizeň

  1. Keříky a jejich skóre načíst ze vstupu do obousměrného spojového seznamu.
  2. Simulovat a počítat sklízecí cykly od prvního až po poslední, kdy už není co sklidit. Keříky ke sklizni uchovávat v pomocné frontě.
  3. Simulovat nanečisto 1. sklízecí cyklus. Projít celý spojový seznam a kontrolovat podmínku skliditelnosti u každého keříku. Je-li keřík skliditelný, označit si u něj, že bude sklizen v 1. sklízecím cyklu a zařadit jej do pomocné fronty.
  4. Opakovat, dokud není pomocná fronta prázdná:
    • Vyjmout keřík z fronty. Zkontrolovat zda následník v seznamu lze sklidit vůči předchůdci (v příštím cyklu).
    • Pokud lze sklidit, zapamatovat si u něj čas sklizně o jedna větší než u keříku vytaženého z fronty.
    • Sklidit keřík, který byl vytažen z fronty (odstranit ho ze seznamu).
  5. Vypsat čas sklizně posledního keříku vytaženého z fronty.

Příklad zdrojového kódu:

import java.util.Scanner; /** * Ukol1 */ public class PalivaSklizen { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int pocetKeru = Integer.parseInt(sc.nextLine()); String[] kereTxT = sc.nextLine().split(" "); sc.close(); int[] kere = new int[pocetKeru]; int[] maxPocetProKazdeho = new int[pocetKeru]; for (int i = 0; i < maxPocetProKazdeho.length; i++) { maxPocetProKazdeho[i]--; } for (int i = 0; i < kere.length; i++) { kere[i] = Integer.parseInt(kereTxT[i]); } int maxPocetSklizni = 0; for (int i = pocetKeru - 1; i >= 0; i--) { int maxThis = checkUsability(i, kere, maxPocetProKazdeho); if (maxThis > maxPocetSklizni) { maxPocetSklizni = maxThis; } } System.out.println(maxPocetSklizni); } private static int checkUsability(int givenIndex, int[] array, int[] maxPocty) { int maxNeeded = 0; int lastKer = 0; if (maxPocty[givenIndex] >= 0) { return maxPocty[givenIndex]; } if (givenIndex == 1 && array[1] == array[0]) return 0; for (int i = givenIndex; i >= 0; i--) { if (array[i] >= array[givenIndex]) { if (i == 0) maxNeeded = 0; else if (lastKer > array[i]) { maxNeeded += (1 - checkUsability(i + 1, array, maxPocty)); } else maxNeeded++; } else { break; } lastKer = array[i]; } maxPocty[givenIndex] = maxNeeded; return maxNeeded; } }

Stupnice pálivosti

  1. Načíst ze vstupu první řádku a dle její délky určit počet teploměrů. Vytvořit si pole celých čísel o příslušné velikosti.
  2. Načítat jednotlivé řádky a inkrementovat hodnoty v poli na těch indexech, kde se nachází symbol rtuti teploměru, inkrementovat hodnotu.
  3. Načtením všech řádek si určit maximální hodnotu.
  4. Pole čísel seřadit libovolným řadícím algoritmem sestupně.
  5. Vykreslit seřazené pole jako teploměry pálivosti po řádkách. Pro určení, zda pro příslušný teploměr v dané řádce vykreslovat znak rtuti, použít maximální hodnotu.

Příklad zdrojového kódu:

#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int length = 0; int working = 1; while (working) { int tlength = 0; int hot = 0; char c; while ((c = getchar()) != EOF && working) { if (c == '\n') { break; } else { switch (c) { case 'o': working = 0; break; case ' ': case '.': tlength++; break; case '|': tlength++; hot++; break; } } } if (!working) { break; } length = tlength; for (int i = 0; i < length; i++) { if ((i + 1) % 2 == 0) { printf(" "); } else if (hot > 0) { hot--; printf("|"); } else { printf("."); } } printf("\n"); } for (int i = 0; i < length; i++) { if ((i + 1) % 2 == 0) { printf(" "); } else { printf("o"); } } printf("\n"); return 0; }

Výběrové zemědělství

  1. Pro každý testovací případ načíst ze vstupu řetězce udávající původní (A) a požadovanou (B) podobu záhonu.
  2. Použijeme 2D dynamické programování. Postupovat přes prefixy A a B od triviální velikosti po plný řetězec.
  3. Výpočet realizovat přes pomocnou tabulku M: M[i][j] = true, pokud je řetězec B[0...(i-1)] transformovatelný z řetězce A[0...(j-1)], jinak false.
  4. Vyplnění tabulky začít nastavením M[i][j] na false pro celou tabulku. Dále nastavit diagonálu M[i][i] pro i od 0 do délky kratšího řetězce z A a B včetně. Pokud jde předchozí prefix délky i-1 transformovat a znak A[i] je malé nebo velké B[i], nastavit true, jinak false.
  5. Vyplnit tabulku po řádkách vždy od sloupce za diagonálou. M[i][j] nastavit true, pokud je splněna alespoň jedna z podmínek, jinak false:
    • Vynechat znak A[i], pokud je malý, pak musí odpovídat prefix s předchozím řetězcem.
    • Použít znak A[j], pokud je velký.
    • Změnit znak A[j] z malého na velký a použít ho.
  6. Vypsat hodnotu z posledního prvku 2D tabulky M (pro true vypsat „ano“, pro false „ne“).

Příklad zdrojového kódu:

import java.util.*; public class VyberoveZemedelstvi { public static void main(String[] args) { Scanner in = new Scanner(System.in); int count = in.nextInt(); loop: for (int i = 0; i < count; i++) { char[] possible = in.next().toCharArray(); char[] wanted = in.next().toCharArray(); Set<Integer> curr = new HashSet<>(1); curr.add(-1); for (char c : possible) { boolean isOptional = Character.isLowerCase(c); Set<Integer> newSet = new HashSet<>(isOptional ? curr.size() * 2 : curr.size()); for (int num : curr) { if (isOptional) { if (wanted.length >= num + 2 && Character.toUpperCase(c) == wanted[num + 1]) newSet.add(num + 1); newSet.add(num); } else { if (wanted.length >= num + 2 && c == wanted[num + 1]) newSet.add(num + 1); } } if (newSet.isEmpty()) { System.out.println("NE"); continue loop; } curr = newSet; } System.out.println(curr.stream().max(Integer::compareTo).get() + 1 == wanted.length ? "ANO" : "NE"); } } }

Výroba omáček

  1. Načíst ze vstupu požadovaný počet lahviček a časy výroby jednotlivých míst.
  2. Určovat celkovou produkci pro konkrétní časy mocninné řady 2kpočínaje. Zjistit tak výrobu v čase 1, 2, 4, 8, 16, 32 atd.
  3. Celkovou výrobu v daném čase určit celočíselným dělením daného času časem výroby jednotlivých míst pro každé výrobní místo a výsledky sečíst.
  4. Určování výroby pro rostoucí čas ukončit, jakmile výroba přesáhne požadovaný počet lahviček.
  5. Pomocí binárního vyhledávání najít nejmenší čas nutný k výrobě požadovaného počtu lahviček. Jako počáteční hranice vyhledávání použít předposlední (menší než požadovaný počet) a poslední (větší než požadovaný počet) spočtenou produkci.
  6. Produkci v konkrétním čase potřebnou pro binární vyhledání počítat stejným způsobem jako výše pro čas rostoucí mocninnou řadou.
  7. Vypsat čas nalezený binárním vyhledáváním.

Příklad zdrojového kódu:

#include <iostream> #include <vector> #include <algorithm> using namespace std; bool check(const vector<long long> &pi, long long l, long long cas) { long long x{}; for (long long i{}; i < pi.size(); ++i) { x += cas / pi[i]; } return x >= l; } int main() { long long v, l, c = 0; cin >> v >> l; vector<long long> pi(v); for (int i{}; i < v; ++i) { cin >> pi[i]; } long long min = 1; long long max = *max_element(pi.begin(), pi.end()) * l; while (min < max) { long long mid = min + (max - min) / 2; if (check(pi, l, mid)) { max = mid; } else { min = mid + 1; } } cout << min << endl; return 0; }

Zalévání papriček

  1. Načíst ze vstupu počet keříků a naměřených vzdáleností.
  2. Všechny naměřené vzdálenosti načíst a vytvořit z nich graf, kde keříky odpovídají vrcholům a naměřené vzdálenosti hranám.
  3. Pro reprezentaci grafu lze využít např. matici sousednosti (počet vrcholů je dostatečně malý).
  4. Algoritmem pro hledání minimální kostry grafu určit délku minimální kostry.
  5. Vypsat nalezenou délku minimální kostry grafu.

Příklad zdrojového kódu:

program U2425; const MAX_N=1000; MAX_M=2000; type tV=record s, e, d: LongInt; end; var keriky: array[0..MAX_N-1] of LongInt; vzdalenosti: array[0..MAX_M-1] of tV; count, vCount, link, min, i, j: LongInt; temp: tV; function NajdiKoren(uzel: LongInt): LongInt; begin if keriky[uzel]=uzel then NajdiKoren:=uzel else NajdiKoren:=NajdiKoren(keriky[uzel]); end; procedure SpojKoren(uzel1, uzel2: LongInt); begin keriky[NajdiKoren(uzel1)]:=NajdiKoren(uzel2); end; begin ReadLn(count); ReadLn(vCount); for i:=0 to vCount-1 do begin Read(vzdalenosti[i].s); Read(vzdalenosti[i].e); ReadLn(vzdalenosti[i].d); end; for i:=0 to count-1 do keriky[i]:=i; for i:=0 to vCount-2 do begin for j:=i+1 to vCount-1 do begin if (vzdalenosti[i].d-vzdalenosti[j].d)>0 then begin temp:=vzdalenosti[i]; vzdalenosti[i]:=vzdalenosti[j]; vzdalenosti[j]:=temp; end; end; end; min:=0; link:=0; for i:=0 to vCount-1 do begin if link=count-1 then break; if NajdiKoren(vzdalenosti[i].s)<>NajdiKoren(vzdalenosti[i].e) then begin min:=min+vzdalenosti[i].d; SpojKoren(vzdalenosti[i].s, vzdalenosti[i].e); Inc(link); end; end; WriteLn(min); ReadLn; end.

Zeď proti škůdcům

  1. Načíst ze vstupu maximální index, počet příkazů a pak načítat jednotlivé příkazy.
  2. Použít zametací algoritmus, kdy se „zametá“ podél zdi a udržuje se aktuální výška zdi.
  3. Z každého příkazu na vstupu vytvořit dvě události změny výšky (zvýšení zdi na počátečním indexu a snížení na koncovém).
  4. Události seřadit podle jejich indexu vzestupně. V případě shody indexů upřednostnit událost zvýšení zdi před snížením zdi.
  5. Projít události v tomto pořadí a přičítat změny výšky do pomocné proměnné, ve které vyjde maximum
  6. Vypsat nalezené maximum.

Příklad zdrojového kódu:

#include <iostream> #include <vector> using namespace std; int main() { int n, p; cin >> n >> p; vector<long long> vysky(n + 2, 0); for (int i = 0; i < p; ++i) { int z, k, v; cin >> z >> k >> v; vysky[z] += v; vysky[k + 1] -= v; } long long nejvyssi=0, vyska = 0; for (int i = 1; i <= n; ++i) { vyska += vysky[i]; nejvyssi = max(nejvyssi, vyska); } cout << nejvyssi; return 0; }

Finálové úlohy - řešení

Nejprve je stručně popsán způsob, jakým je možno úlohu řešit. Následně je ukázán zdrojový kód řešení vytvořeného jedním z finalistů.

K nahlédnutí je rovněž prezentace s popisem řešení předvedená po skončení finále.

Kivule berou

  1. Načíst si pozice jednotlivých kulových karet a uložit si ho např. do pole boolean reprezentující zamíchaný balíček karet. Hodnoty karet nejsou důležité, jde pouze o to, zda to jsou nebo nejsou kule.
  2. Připravit si datovou strukturu umožňující přidávat i odebírat prvky ze začátku i z konce (modifikovaná fronta implementovaná např. obousměrným spojovým seznamem). Tuto strukturu použít k reprezentaci balíčků karet obou hráčů a karet na stole.
  3. Simulovat průběh hry - rozdat karty oběma hráčům, přesouvání karet mezi kartami na stole a kartami hráčů. Je potřeba dbát na směr dle rubu a líce karet a podle toho volit správné odebírání a přidávání do datových struktur.
  4. Hru ukončit v okamžiku, kdy jeden z hráčů nemá v datové struktuře žádné karty.
  5. Vypsat číslo vítězného hráče.

Příklad zdrojového kódu:

#include <iostream> #include <cmath> #include <algorithm> #include <vector> #include <string> #include <queue> #include <unordered_set> using namespace std; int main() { unordered_set<int> s; for (int i = 0; i < 8; i++) { int x; cin >> x; s.insert(x); } queue<int> prvni, druhy; vector<int> stul; for (int i = 32; i>0; i--) { if (i % 2 == 1) druhy.push(i); else prvni.push(i); } while (prvni.size()<32 && druhy.size()<32) { if (!druhy.empty() && druhy.size()<32) { stul.push_back(druhy.front()); if (s.find(druhy.front()) != s.end()) { for (int i = 0; i < stul.size(); i++) { prvni.push(stul[i]); } stul.clear(); } druhy.pop(); } if (!prvni.empty() && prvni.size()<32) { stul.push_back(prvni.front()); if (s.find(prvni.front()) != s.end()) { for (int i = 0; i < stul.size(); i++) { druhy.push(stul[i]); } stul.clear(); } prvni.pop(); } } if (prvni.size() == 32) cout << 2 << endl; else cout << 1 << endl; }

Líný cyklista

  1. Načíst si první řádku uniformní mřížky a podle počtu čísel na ní určit velikost mřížky (tj. šířku i výšku).
  2. Načíst zbývající řády a uložit si výšky v jednotlivých bodech mřížky např. do 2D pole.
  3. Načíst pozici domova, pozici univerzity a vzdálenost sousedních bodů mřížky.
  4. Z načtených bodů uniformní mřížky vytvořit graf, kdy body tvoří vrcholy a horizontální a vertikální spojnice bodů tvoří hrany.
  5. Spočítat ohodnocení jednotlivých hran jako čas potřebný k projetí po hraně pomocí vzorce uvedeného v zadání.
  6. Použít algoritmus pro hledání nejkratší cesty v ohodnoceném grafu (např. Dijkstrův algorimus) a najít délku (tj. dobu trvání) nejkratší cesty.
  7. Nalezenou délku převést na sekundy (pokud nebylo učiněno již dříve) a vypsat.

Příklad zdrojového kódu:

#include <iostream> #include <cmath> #include <algorithm> #include <sstream> #include <string> #include <vector> #include <queue> using namespace std; struct pohyb { float cas; pair<int, int> poz; }; struct compare { bool operator()(pohyb a, pohyb b) { return a.cas > b.cas; } }; void B() { string st; getline(cin, st); stringstream s(st); vector<int> tempv; string temp; while (s >> temp) { tempv.push_back(stoi(temp)); } int n = tempv.size(); vector<vector<int>> mapa (n, vector<int>(n)); for (int i = 0; i < tempv.size(); i++) mapa[i][0] = tempv[i]; for (int i = 1; i < n; i++) { for (int j = 0; j < n; j++) { cin >> mapa[j][i]; } } pair<int, int> start; pair<int, int> cil; cin >> start.first >> start.second >> cil.first >> cil.second; float d; cin >> d; priority_queue <pohyb, vector<pohyb>, compare> halda; pohyb novy; novy.cas = 0; novy.poz = start; halda.push(novy); vector<pair<int, int>> pohyby = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} }; vector<vector<float>> casy(n, vector<float>(n, -1)); casy[start.first][start.second] = 0; //for (int i = 0; i < n; i++) //{ // for (int j = 0; j < n; j++) // { // cout << mapa[j][i] << " "; // } // cout << endl; //} while (!halda.empty()) { pohyb poz = halda.top(); halda.pop(); if ((casy[poz.poz.first][poz.poz.second] != -1) && (casy[poz.poz.first][poz.poz.second] != 0)) continue; //cout << poz.poz.first << " " << poz.poz.second << " dsfdsfsd" << endl; casy[poz.poz.first][poz.poz.second] = poz.cas; if ((poz.poz.first == cil.first) && (poz.poz.second == cil.second)) { break; } for (int i = 0; i < 4; i++) { if ((poz.poz.first + pohyby[i].first >= 0) && (poz.poz.first + pohyby[i].first < n) && (poz.poz.second + pohyby[i].second >= 0) && (poz.poz.second + pohyby[i].second < n)) { pohyb pridej; pridej.poz.first = poz.poz.first + pohyby[i].first; pridej.poz.second = poz.poz.second + pohyby[i].second; if (casy[pridej.poz.first][pridej.poz.second] != -1) continue; float vert = (float)(mapa[pridej.poz.first][pridej.poz.second] - mapa[poz.poz.first][poz.poz.second]) / (float)1000; float uhel = atan(vert / d) * 180 / 3.1415926535; float vzd = sqrt(d * d + vert * vert); float rychlost = max((float)30 - (float)uhel, (float)4); pridej.cas = poz.cas + ((float)vzd / (float)rychlost); //cout << pridej.poz.first << " " << pridej.poz.second << endl; //cout << vert << endl; //cout << uhel << endl; //cout << vzd << endl; //cout << rychlost << endl; //cout << pridej.cas << endl; //cout << endl; halda.push(pridej); } } } //for (int i = 0; i < n; i++) //{ // for (int j = 0; j < n; j++) // { // cout << casy[j][i] << " "; // } // cout << endl; //} cout << round(casy[cil.first][cil.second] * 3600) ; } int main() { B(); return 0; }

Okresní silnice

  1. Načíst si preferované rychlosti jednotlivých vozidel.
  2. Pro načtená vozidla provést simulaci pohybu vozidel po malých časových krocích.
  3. Vozidla udržovat ve dvou seznamech - auta na silnici v jejich pořadí a odstavená auta.
  4. Dokud není první auto v cíli pro každé auto na silnici provést v každém kroku:
    • Posunout vozidlo na novou pozici.
    • Akumulovat čas v koloně.
    • Akumulovat čas porušování předpisů.
    • Upravit příznak lze-předjet.
    • Zkontrolovat vypršení časových limitů případně odstavení auta (přesun ze silnice do odstavených případně obráceně).
  5. Seřadit aut - pokud jsou na stejné pozici, pokud může předjet a podle rychlosti, jinak podle pozice

Příklad zdrojového kódu:

Tuto úlohu žádný soutěžící nevyřešil.

Poštovní pevnost

  1. Načíst si počet emailů.
  2. Následně načítat příslušný počet řádek jako text.
  3. Pokud načtená řádka nezačíná na hvězdičku, inkrementovat čítač úspěšně doručených emailů.
  4. Výsledek vypočítat jako podíl počtu úspěšně doručených emailů a celkového počtu emailů v procentech. Pozor na celočíselné dělení, je třeba provést reálné dělení dvou celých čísel.
  5. Výsledek vypsat na dvě desetinná místa v požadovaném formátu.

Příklad zdrojového kódu:

program U2434; uses sysutils, math; var count, i, a, b: LongInt; s: String; begin ReadLn(count); a:=0; for i:=0 to count-1 do begin ReadLn(s); if s[1]='*' then Inc(a); end; b:=count-a; WriteLn('Uspesnost: ', FloatToStrF(SimpleRoundTo((b/count)*100, -2), ffFixed, 0, 2)); ReadLn; end.

Schodiště

  1. Načíst si maximální vzdálenost, počet bodů a souřadnice jednotlivých bodů a seřadit si body podle souřadnice x od nejnižšího bodu k nejvyššímu.
  2. Rozdělit si chůzi robota na dvě části - cestu po schodišti vzhůru a cestu po schodišti dolů. Řešit pomocí dynamického programování.
  3. Body zpracovávat v pořadí jeden za druhým.
  4. Uvažovat tři parametry:
    1. i - hraniční bod východní cesty i .. n - 1,
    2. j - hraniční bod západní cesty n - 1 .. j,
    3. k - další bod v pořadí zpracování bodů.
  5. Parametr k lze určit z parametrů i a j jako max(i, j) + 1.
  6. Mezivýsledky pro i a j ukládat do tabulky DélkaTrasy[i, j] následovně:
    • pro k = n - 1: DélkaTrasy[i, j] = vzdálenostBodů(i, k) + vzdálenostBodů(k, j),
    • jinak: DélkaTrasy[i, j] = min(DélkaTrasy[k, j] + vzdálenostBodů(i, k), DélkaTrasy[i, k] + vzdálenostBodů(k, j)).
  7. Po vyplnění tabulky bude řešení úlohy v DélkaTrasy[0, 0].

Příklad zdrojového kódu:

Tuto úlohu žádný soutěžící nevyřešil.