J'ai besoin de trouver le plus grand carré de 1 dans un fichier géant plein de 1 et de 0. Je sais que je dois utiliser la programmation dynamique. Je le stocke dans un tableau 2D. Toute aide avec l'algorithme pour trouver le plus grand carré serait formidable, merci!
exemple d'entrée:
1 0 1 0 1 0
1 0 1 1 1 1
0 1 1 1 1 1
0 0 1 1 1 1
1 1 1 1 1 1
répondre:
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
Mon code jusqu'à présent:
int Square (Sq[int x][int y]) {
if (Sq[x][y]) == 0) {
return 0;
}
else {
return 1+MIN( Sq(X-1,Y), Sq(X,Y-1), Sq(X-1,Y-1) );
}
}
(en supposant des valeurs déjà entrées dans le tableau)
int main() {
int Sq[5][6]; //5,6 = bottom right conner
int X = Square(Sq[5][6]);
}
Comment puis-je continuer à partir de là?
Voici un croquis de la solution:
Pour chacune des cellules, nous garderons un compteur de la taille d'un carré en utilisant cette cellule en haut à gauche. Clairement, toutes les cellules avec 0 auront 0 comme nombre.
Commencez à itérer à partir de la cellule en bas à droite et allez en bas à gauche, puis allez à une rangée et répétez.
À chaque analyse, procédez comme suit:
count=0
count=1
max_count
Pour garder une trace du nombre maximum jusqu'à présent.À la fin de la traversée de la matrice, max_count
Aura la valeur souhaitée.
La complexité n'est plus que le coût de la traversée de la matrice.
Voici à quoi ressemblera la matrice après la traversée. Les valeurs entre parenthèses sont les nombres, c'est-à-dire le plus grand carré qui peut être créé en utilisant la cellule en haut à gauche.
1(1) 0(0) 1(1) 0(0) 1(1) 0(0)
1(1) 0(0) 1(4) 1(3) 1(2) 1(1)
0(0) 1(1) 1(3) 1(3) 1(2) 1(1)
0(0) 0(0) 1(2) 1(2) 1(2) 1(1)
1(1) 1(1) 1(1) 1(1) 1(1) 1(1)
def max_size(mat, ZERO=0):
"""Find the largest square of ZERO's in the matrix `mat`."""
nrows, ncols = len(mat), (len(mat[0]) if mat else 0)
if not (nrows and ncols): return 0 # empty matrix or rows
counts = [[0]*ncols for _ in xrange(nrows)]
for i in reversed(xrange(nrows)): # for each row
assert len(mat[i]) == ncols # matrix must be rectangular
for j in reversed(xrange(ncols)): # for each element in the row
if mat[i][j] != ZERO:
counts[i][j] = (1 + min(
counts[i][j+1], # east
counts[i+1][j], # south
counts[i+1][j+1] # south-east
)) if i < (nrows - 1) and j < (ncols - 1) else 1 # edges
return max(c for rows in counts for c in rows)
LSBRA(X,Y)
signifie "le plus grand carré avec en bas à droite en X, Y"
Pseudocode:
LSBRA(X,Y):
if (x,y) == 0:
0
else:
1+MIN( LSBRA(X-1,Y), LSBRA(X,Y-1), LSBRA(X-1,Y-1) )
(Pour les cellules Edge, vous pouvez ignorer la partie MIN et renvoyer simplement 1 si (x, y) n'est pas 0.)
Travaillez en diagonale à travers la grille en "vagues", comme suit:
0 1 2 3 4
+----------
0 | 1 2 3 4 5
1 | 2 3 4 5 6
2 | 3 4 5 6 7
3 | 4 5 6 7 8
ou alternativement, travaillez de gauche à droite, de haut en bas, tant que vous remplissez des cellules Edge.
0 1 2 3 4
+----------
0 | 1 2 3 4 5
1 | 6 7 8 9 .
2 | . . . . .
3 | . . . . .
De cette façon, vous ne rencontrerez jamais un calcul où vous n'avez pas encore calculé les données nécessaires - donc tous les LSBRA()
"appels" ne sont en fait que des tables de recherche de vos résultats de calcul précédents (d'où la programmation dynamique aspect).
Pourquoi ça marche
Afin d'avoir un carré avec un coin inférieur droit en X, Y - il doit contenir les carrés qui se chevauchent d'une dimension en moins qui touchent chacun des 3 autres coins. En d'autres termes, avoir
XXXX
XXXX
XXXX
XXXX
vous devez aussi avoir ...
XXX. .XXX .... ....
XXX. .XXX XXX. ....
XXX. .XXX XXX. ....
.... .... XXX. ...X
Tant que vous avez ces 3 carrés (chacun des contrôles LSBRA) de taille N plus le carré actuel est également "occupé", vous aurez un carré de taille (N + 1).
Le premier algorithme qui me vient à l'esprit est:
Je ne vais pas vous montrer l'implémentation car elle est assez simple et votre problème ressemble à des devoirs. En outre, il existe probablement des moyens beaucoup plus efficaces de le faire, car cela deviendra lent si l'entrée était très grande.
Soit la matrice d'entrée est M
: n x m
T[i][j]
est la matrice DP qui contient le plus grand côté carré avec des carrés en bas à droite (i,j)
.
Règle générale pour remplir le tableau:
if (M[i][j] == 1) {
int v = min(T[i][j-1], T[i-1][j]);
v = min(v, T[i-1][j-1]);
T[i][j] = v + 1;
}
else
T[i][j] = 0;
La taille du carré résultant est la valeur maximale dans T
.
Remplissage T[i][0]
et T[0][j]
est trivial.
Je ne sais pas si cet algo peut être utilisé pour votre fichier énorme, mais vous n'avez pas besoin de stocker la matrice entière T
mais uniquement la version actuelle et précédente lignes uniquement.
Les notes suivantes peuvent aider à comprendre l'idée générale:
La clé ici est que vous pouvez garder une trace de la racine de la zone au lieu de la zone réelle, en utilisant la programmation dynamique.
L'algorithme est le suivant:
Stockez un tableau 2D d'entiers appelé max-carré, où un élément à l'indice i, j représente la taille du carré dans lequel il se trouve avec i, j étant le coin inférieur droit. (si max [i, j] = 2, cela signifie que l'indice i, j est le coin inférieur droit d'un carré de taille 2 ^ 2 = 4)
Pour chaque indice i, j:
si en i, j l'élément est 0, alors définissez max-square i, j sur 0.
sinon:
Trouver le minimum de max-square [i - 1, j] et max-square [i, j - 1] et max-square [i - 1] [j -1]. définissez max-square [i, j] sur 1 + le minimum de 3. Inductivement, vous finirez par remplir le tableau max-square. Trouvez/ou gardez une trace de la valeur maximale dans le processus, renvoyez cette valeur ^ 2.
Jetez un oeil à ces solutions que les gens ont proposées: https://leetcode.com/discuss/questions/oj/maximal-square?sort=votes
OK, la manière la plus inefficace mais simple serait:
sélectionnez le premier élément. cochez si 1, si c'est le cas, vous avez un carré 1x1.
cochez une en dessous et une à droite, si 1, puis cochez la ligne 2 col 2, si 1, carré 2x2.
cochez la ligne 3 col 1, col 2 et col 3, plus la ligne 1 col 3, la ligne 2 col 3, si 1, 3x3.
Donc, fondamentalement, vous continuez à développer la ligne et le col ensemble et vérifiez toutes les cellules à l'intérieur de leurs limites. Dès que vous atteignez un 0, il est cassé, vous vous déplacez donc sur 1 point d'affilée et recommencez.
À la fin du rang, passez au rang suivant.
jusqu'à la fin.
Vous pouvez probablement voir comment ceux-ci s'intègrent dans les boucles while, etc., et comment &&
s peut être utilisé pour vérifier les 0, et en le regardant, vous remarquerez peut-être aussi comment il peut être accéléré. Mais comme l'autre réponse vient de le mentionner, cela ressemble un peu à des devoirs, nous laisserons donc le code réel à vous.
Bonne chance!
Soit N la quantité de cellules du tableau 2D. Il existe un algorithme très efficace pour lister tous les rectangles vides maximum. Le plus grand carré vide se trouve à l'intérieur d'un de ces rectangles vides, et le trouver est trivial une fois que la liste des rectangles vides maximum a été calculée. Un article présentant un O(N) algorithme pour créer une telle liste peut être trouvé sur www.ulg.ac.be/telecom/rectangles ainsi que le code source (non optimisé). Notez qu'il existe une preuve (voir l'article) que le nombre de plus grands rectangles vides est délimité par N. Par conséquent, la sélection du plus grand carré vide peut être effectuée dans O (N), et la méthode globale est également O (N). En pratique, cette méthode est très rapide. L'implémentation est très facile à faire, car le code entier ne doit pas dépasser 40 lignes de C (l'algorithme pour lister tous les rectangles vides maximum prend environ 30 lignes de C ).