2724 - LSQ

De la Universitas MediaWiki

Cerința

Se dă o matrice binară (valori 0 și 1). Să se determine care este latura maximă a unui pătrat cu proprietatea că acesta are pe marginea sa doar valori 1.

Date de intrare

Fișierul de intrare lsq.in conține pe prima linie numerele N și M, reprezentând numărul de linii și numărul de coloane ale matricei, apoi N linii, pe fiecare câte M valori 0 sau 1, neseparate prin niciun spațiu, reprezentând elementele matricei..

Date de ieșire

Fișierul de ieșire lsq.out va conține pe prima linie numărul L, reprezentând lungimea maximă a laturii unui pătrat ce conține doar 1 pe marginea sa. Consola va afișa un mesaj de validare a datelor ("Input valid" sau "Input invalid" după caz).

Restricții și precizări

  • 1 ⩽ N, M ⩽ 1000
  • Se consideră pătrat și cel de latură 1 (conține doar un element).

Exemplu

lsq.in
7 7
0000000
0111100
0101111
0100101
0111111
0000011
0000011
lsq.out
4
Consola
Input valid

Explicație

0 0 0 0 0 0 0
0 1 1 1 1 0 0
0 1 0 1 1 1 1
0 1 0 0 1 0 1
0 1 1 1 1 1 1
0 0 0 0 0 1 1
0 0 0 0 0 1 1

Rezolvare

Nmax = 1005


def compute_matrices(N, M, A):
    LDL = [[0] * M for _ in range(N)]
    CDL = [[0] * M for _ in range(N)]
    LRU = [[0] * M for _ in range(N)]
    CRU = [[0] * M for _ in range(N)]

    for i in range(N):
        for j in range(M):
            if A[i][j] == 1:
                LDL[i][j] = 1 + LDL[i][j - 1] if j > 0 else 1
                CDL[i][j] = 1 + CDL[i - 1][j] if i > 0 else 1

    for i in range(N - 1, -1, -1):
        for j in range(M - 1, -1, -1):
            if A[i][j] == 1:
                LRU[i][j] = 1 + LRU[i][j + 1] if j < M - 1 else 1
                CRU[i][j] = 1 + CRU[i + 1][j] if i < N - 1 else 1

    return LDL, CDL, LRU, CRU


def find_largest_square(N, M, A):
    LDL, CDL, LRU, CRU = compute_matrices(N, M, A)
    ans = 0
    for i in range(N):
        for j in range(M):
            for L in range(min(LDL[i][j], CDL[i][j]), ans, -1):
                if L <= min(LRU[i - L + 1][j - L + 1], CRU[i - L + 1][j - L + 1]):
                    ans = L
                    break
    return ans

def validate_input(n: int, m: int) -> bool:
    return 1 <= n <= 1000 and 1 <= m <= 1000

if __name__ == "__main__":
    with open("lsq.in", "r") as fin, open("lsq.out", "w") as fout:
        N, M = map(int, fin.readline().split())
        A = [list(map(int, fin.readline().strip())) for _ in range(N)]
        if not validate_input(N, M):
            print("Input invalid")
            return
        else:
            print("Input valid")
        ans = find_largest_square(N, M, A)
        fout.write(str(ans) + "\n")

Explicație cod

Acest program calculează dimensiunea celui mai mare pătrat format numai din cifra 1 într-o matrice bidimensională dată.

Funcția `compute_matrices` calculează patru matrici: `LDL`, `CDL`, `LRU`, `CRU`, fiecare fiind de aceeași dimensiune ca matricea de intrare `A`. Matricile `LDL` și `CDL` conțin lungimile celor mai lungi segmente consecutive de cifra 1 din stânga și, respectiv, de sus de fiecare celulă, iar matricile `LRU` și `CRU` conțin lungimile celor mai lungi segmente consecutive de cifra 1 din dreapta și, respectiv, de jos de fiecare celulă.

În denumirea matricelor din funcția `compute_matrices`, primele trei litere reprezintă inițialele direcțiilor de la care începe numărătoarea segmentelor de cifra 1. Astfel, matricea `LDL` conține lungimile segmentelor consecutive de cifra 1 din stânga fiecărei celule, începând de la stânga și mergând spre dreapta, matricea `CDL` conține lungimile segmentelor consecutive de cifra 1 de sus fiecărei celule, începând de sus și mergând în jos, iar matricea `LRU` conține lungimile segmentelor consecutive de cifra 1 din dreapta fiecărei celule, începând de la dreapta și mergând spre stânga, iar matricea `CRU` conține lungimile segmentelor consecutive de cifra 1 de jos fiecărei celule, începând de jos și mergând în sus.

Funcția `find_largest_square` parcurge fiecare celulă din matricea de intrare și, pentru fiecare celulă, verifică dacă poate fi colțul stânga-sus al unui pătrat și, în caz afirmativ, încearcă să-l mărească progresiv până la limita minimă dintre lungimile segmentelor de cifra 1 din matricile `LDL`, `CDL`, `LRU` și `CRU`.

Funcția `validate_input` verifică dacă dimensiunile matricei de intrare sunt între 1 și 1000 inclusiv, iar blocul `if __name__ == "__main__":` citește datele de intrare din fișierul "lsq.in", validează dimensiunile matricei de intrare, calculează dimensiunea celui mai mare pătrat de cifra 1 și scrie rezultatul în fișierul "lsq.out".