|
Autorské riešenie
[stiahni
py]
Úlohou súťažiacich bolo vygenerovať mriežku veľkosti n×m so spinmi
+1 a -1, ktoré môžeme interpretovať napríklad ako stavy
neurónov v Hopfieldovej sieti. Základnou podmienkou úlohy bolo, aby
v každom riadku aj v každom stĺpci mriežky existovala aspoň jedna bunka
s hodnotou +1 a zároveň aspoň jedna bunka s hodnotou -1.
Inými slovami, v žiadnom riadku ani stĺpci nesmeli byť všetky hodnoty rovnaké.
Priamy konštrukčný postup, ktorý by túto podmienku splnil pre ľubovoľné
rozmery mriežky, nie je na prvý pohľad triviálny. Preto je prirodzené
hľadať riešenie, ktoré kombinuje jednoduchý počiatočný nápad
s postupným dolaďovaním výsledku.
Jedna z možných myšlienok riešenia je nasledujúca:
-
Rýchly štart - vytvorenie platnej mriežky:
Najskôr si vytvoríme mriežku, ktorá už od začiatku spĺňa požadované
podmienky. To dosiahneme tak, že do všetkých buniek nastavíme hodnotu
+1 a následne po hlavnej uhlopriečke mriežky nastavíme hodnotu
-1. Tým zabezpečíme, že každý riadok aj každý stĺpec obsahuje
aspoň jednu hodnotu -1.
Ak mriežka nie je štvorcová (n != m), uhlopriečka pokryje len časť
riadkov alebo stĺpcov. Preto v "dlhšom" smere ešte doplníme hodnotu
-1 na okraji mriežky tam, kde sa uhlopriečka skončí.
Tým je zaručené, že aj zvyšné riadky alebo stĺpce budú obsahovať
obe hodnoty +1 aj -1.
-
Náhodné lokálne úpravy - zlepšovanie riešenia:
Po vytvorení počiatočnej mriežky už máme korektné riešenie, ktoré však
má veľmi pravidelnú štruktúru. Preto ho ďalej "rozrušíme" pomocou
náhodných lokálnych zmien.
V každom kroku náhodne vyberieme jednu bunku mriežky a skúšame jej
priradiť hodnotu +1 alebo -1. Takúto zmenu však
povolíme iba vtedy, ak po nej zostane v príslušnom riadku aj stĺpci
aspoň jedna hodnota +1 aj aspoň jedna hodnota -1.
Aby bolo možné túto podmienku kontrolovať efektívne, počas celého
algoritmu si priebežne udržiavame počty buniek s hodnotou +1
v každom riadku a v každom stĺpci. Vďaka tomu vieme v konštantnom čase
rozhodnúť, či je konkrétna zmena prípustná, bez potreby opakovane
prechádzať celú mriežku.
Nasleduje možný zdrojový kód v jazyku Python:
def mriezka(n, m):
if n < 2 or m < 2:
print("n aj m musia byť aspoň 2")
return
# štart: všade +1
A = [[1]*m for _ in range(n)]
# -1 po uhlopriečke
d = min(n, m)
for i in range(d):
A[i][i] = -1
# koniec uhlopriečky: -1 na kraji
if n > m:
for i in range(d, n):
A[i][m-1] = -1
if m > n:
for j in range(d, m):
A[n-1][j] = -1
# počty +1 v riadkoch a stĺpcoch
r = [sum(x == 1 for x in A[i]) for i in range(n)]
c = [sum(A[i][j] == 1 for i in range(n)) for j in range(m)]
def moze(i, j, v):
if A[i][j] == v:
return False
ri = r[i] + (v == 1) - (A[i][j] == 1)
ci = c[j] + (v == 1) - (A[i][j] == 1)
return 1 <= ri <= m-1 and 1 <= ci <= n-1
# náhodné lokálne úpravy
for _ in range(20 * n * m):
i = random.randrange(n)
j = random.randrange(m)
v = random.choice([1, -1])
if moze(i, j, v):
if A[i][j] == 1:
r[i] -= 1; c[j] -= 1
if v == 1:
r[i] += 1; c[j] += 1
A[i][j] = v
return A
Vaše zaujímavé riešenia a najčastejšie chyby
Medzi najzaujímavejšie riešenia patrili tie, ktoré korektne využívali parametre
n a m, vracali mriežku v správnej dátovej štruktúre a systematicky
kontrolovali podmienky pre riadky aj stĺpce. Objavili sa aj kreatívne prístupy,
napríklad dopočítanie posledného riadku podľa stĺpcov alebo postup
"vygeneruj a následne opravuj", ktoré však museli byť realizované veľmi
opatrne, aby sa zachovala platnosť celej mriežky.
Najčastejšie chyby sa týkali kontroly podmienok: cykly while sa buď vôbec
nespustili, alebo uviazli v nekonečnej slučke, často chýbala kontrola stĺpcov
alebo bola kontrolovaná len jedna dimenzia. Veľmi častá bola aj zámena
rozmerov (riadok má dĺžku m, nie n), nesprávne testovanie pomocou
sum, ktoré neodhaľuje prítomnosť oboch spinov, používanie nepovolených
hodnôt (0 alebo reťazce "+1", "-1") a najmä situácie, keď oprava
stĺpca znehodnotila už opravený riadok. V mnohých prípadoch chýbala
dodatočná validácia po opravách, takže výsledná mriežka nebola vždy
garantovane správna.
|