Zadanie
Na Matfyze práve prebiehajú masívne rekonštrukcie. Za pavilónom matematiky stavajú novú budovu, v akvárkach1 vymieňajú staré drevené sedačky a ešte aj KSPáci si znovu prerobili T2ku2. No a rekonštrukcií sa samozrejme nevyhnú ani záchody.
Vedenie by potrebovalo zistiť, koľko záchodových mís musia na rekonštrukciu objednať. Má to ale jeden háčik. Keď projektant kreslil plány budovy, musel si odskočiť a jeho kolega mu tam medzitým dokreslil ešte niekoľko záchodových mís. Na niektorých záchodoch sú teraz iné, väčšie misy, inde sa zase kadejako prekrývajú, čo by možno bolo skvelé na výstave moderného umenia, no na Matfyze by sme radšej chceli funkčné záchody.
Keďže záchodov je na Matfyze veľa, nikomu sa to nechcelo ručne kontrolovať, a preto požiadali KSPákov o pomoc. Tí momentálne ale kvôli organizovaniu Letnej školy Trojstenu nič nestíhajú, a tak túto úlohu nechali na vás.
Úloha
Na vstupe dostanete pôdorys miestnosti pozostávajúci zo znakov
.
a O
, ktoré označujú voľný priestor a časti
záchodovej misy. Záchodová misa veľkosti \(k\) vyzerá ako rovnoramenný trojuholník,
ktorého rohy sú označené znakom O
. Medzi ľavým a pravým
vrcholom je vždy \(2k-1\) prázdnych
políčok (teda označených znakom .
). Spodný vrchol
trojuholníka sa nachádza o \(k\)
políčok nižšie, presne v strede medzi ľavým a pravým vrcholom. Všetok
ostatný priestor, vrátane vnútra misy, je označený znakom
.
.
Záchodové misy v nákrese môžu mať rôzne veľkosti, vždy ale
pozostávajú práve z troch znakov O
a nikdy nie sú otočené
inak.
Vašou úlohou je skontrolovať, či sú všetky záchody správne zakreslené a neprekryvajú sa. V prípade, že je všetko v poriadku, je treba spočítať počet záchodov, ktoré sa na nákrese nachádzajú.
Formát vstupu
Na prvom riadku sa nachádzajú čísla \(s\) a \(r\), ktoré označujú počeť stĺpcov a riadkov nákresu. Na ďalších \(r\) riadkoch nasleduje nákres miestnosti, pričom každý riadok má práve \(s\) znakov.
Formát výstupu
Ak je nákres miestnosti v poriadku, na výstup vypíšte jediné čislo –
počet záchodov, ktoré sa na nákrese nachádzajú. V opačnom prípade
vypíšte Zly nakres
.
Príklad
Input:
8 3
O.O..O.O
.O....O.
........
Output:
2
V tejto miestnosti sú iba 2 záchody rovnakej veľkosti vedľa seba.
Input:
11 5
O.....O....
......O...O
...........
...O.O.OO..
......O....
Output:
3
V ľavom hornom rohu je záchod veľkosti 3, napravo od neho záchod veľkosti 2 a v strede pod nimi je záchod veľkosti 1.
Input:
3 3
O.O
...
...
Output:
Zly nakres
Záchodu chýba tretí znak O
– nákres je
nesprávny.
Na vyriešenie tejto úlohy nebolo treba vymýšlať žiadne komplikované postupy. Stačí nám iba postupne hľadať záchodové misy, kontrolovať či sa v ich vnútri nič nenachádza a spočítať ich.
To urobíme nasledovne: Budeme prechádzať načítaný nákres po riadkoch a hľadať dvojice znakov O
medzi ktorými sú iba znaky .
(bodka), a žiadne iné . V prípade, že k niektorému znaku O
nenájdeme jeho dvojicu, záchod nie je správne zakreslený a teda aj celý nákres je nesprávny.
Každá nájdená dvojica znakov O
je potenciálne záchodovou misou, ktorej veľkosť \(k\) vieme určiť zo vzdialenosti týchto znakov. Vďaka tomu vieme vypočítať, kde sa má nachádzať spodný vrchol trojuholníka reprezentujúceho misu. Následne si už len overíme, či sa na jeho mieste naozaj nachádza znak O
.
Predtým, ako vyhlásime že je táto záchodová misa zakreslená správne, musíme ešte skontrolovať, či sa v jej vnútri naozaj nič nenachádza. Stačí nám jednoduchým cyklom skontrolovať plochu trojuholníka na nasledujúcich \(k\) riadkoch. Ak nájdeme iný znak ako .
, záchod sa s niečím kryje a nákres je nesprávny.
Aby sme sa pri hľadaní ďalších mís nepomýlili, preznačíme si spodný vrchol na nejaký iný znak (napríklad #
), ktorý budeme pri hľadaní ľavého horného vrcholu ignorovať. Nebudeme ho ale ignorovať pri kontrole vnútra trojuholníka, vďaka čomu zistíme prípadné prekrývanie s už skontrolovaným záchodom.
= [int(x) for x in input().split()]
w, h = [list(input()) for _ in range(h)]
m
def check(r, c, s):
global m
if s <= 1:
return False
= s // 2
k if m[r+k][c+k] != 'O':
return False
= '.'
m[r][c] +s] = '.'
m[r][c+k][c+k] = '#'
m[r
for y in range(r, r+k):
for x in range(c+y, c+s-y):
if m[y][x] != '.':
return False
return True
def abort():
print('Zly nakres')
exit()
= None, 0
start, cnt for r, row in enumerate(m):
for c, char in enumerate(row):
if start is None and char == 'O':
= c
start elif char == 'O':
if check(r, start, c-start):
+= 1
cnt = None
start else:
abort()
if start is not None:
abort()
print(cnt)
#include <iostream>
#include <vector>
using namespace std;
typedef vector<vector<char>> vv;
bool check(vv &v, int r, int c, int s) {
if (s <= 1) return false;
int k = s / 2;
if (v[r+k][c+k] != 'O') return false;
'.';
v[r][c] = '.';
v[r][c+s] = '#';
v[r+k][c+k] =
for (int y = r; y < r+k; y++) {
for (int x = c+y; x < c+s-y; x++) {
if (v[y][x] != '.') return false;
}
}
return true;
}
int q() {
"Zly nakres\n";
cout << return 0;
}
int main() {
false);
ios_base::sync_with_stdio(
cin.tie(NULL);
int w, h;
cin >> w >> h;char>(w));
vv v(h, vector<
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
cin >> v[i][j];
}
}
int start = -1, cnt = 0;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (start == -1 && v[i][j] == 'O') {
start = j;else if (v[i][j] == 'O') {
} if (check(v, i, start, j-start)) {
cnt++;1;
start = -else {
} return q();
}
}
}
if (start != -1) {
return q();
}
}
"\n";
cout << cnt <<
return 0;
}
Horné vrcholy trojuholníkov budeme hľadať v celom nákrese, čiže postupne prejdeme všetkých \(r \cdot s\) políčok. Pri kontrole vnútier trojuholníkov skontrolujeme určite menej ako \(r \cdot s\) políčok, keďže plocha pod záchodmi je určite menšia ako celý nákres, a pri prvom zistenom prekrývaní program končí. Výsledná časová zložitosť teda bude \(O(rs)\).
Pamäťová zložitosť bude rovnako \(O(rs)\) - pamätáme si celý nákres a zopár ďalších premenných.
Diskusia
Tu môžte voľne diskutovať o riešení, deliť sa o svoje kusy kódu a podobne.
Pre pridávanie komentárov sa musíš prihlásiť.