Reputation: 21
Ok, so I have to find the biggest "free square" in a grid where some spots are filled, for example, there's this grid:
###---
###---
###---
---###
---###
---###
Where "-" is a filled spot and "#" is a free zone. This is done by filling a nested list: [[###---],[###---],...,[---###]] The inner lists are the vertical lines on the grid. So this grid could be filled in any way, and I'm supposed to find a way to 'calculate' the biggest possible square that can still be filled. In the above example, the output would be: 9. I'll give another example to make things clear:
##########
#####----#
##--#----#
##--#----#
##--#----#
##--#----#
#####----#
##########
-####----#
##########
The output here should be 16, wich is the square from (1,6) to (4,9) (counting from 0)
I hope someone could help me with this problem, thanks in advance! :)
Upvotes: 1
Views: 535
Reputation: 103884
In this particular case (limited to a square as you describe) you can do this.
First, consider a 'square' that is only one character: either -
or #
. It is trivial to see that the size of the square is just testing that one character as either 'taken' or not.
Now consider a 4x4 square:
--
--
or
[['-','-'],
['-','-']]
How do you calculate the max size? You take one element, say the upper left, and test it and its three neighbors if they are taken or not:
>>> sq= [['-','-'],
... ['-','-']]
>>> sq
[['-', '-'], ['-', '-']]
>>> if(all(sq[i][j]=='-' for i in (0,1) for j in (0,1))): print 4
...
4
So generally, take a square and look at its neighbors. You can keep a running count in a matrix that is shaped the same as the target:
st='''\
##########
#####----#
##--#----#
##--#----#
##--#----#
##--#----#
#####----#
##########
-####----#
########## '''
def max_size(mat, taken):
"""Find the largest X or a square not taken in the matrix `mat`."""
nrows, ncols = len(mat), len(mat[0])
assert nrows==ncols
dirs=(0,1),(1,0),(1,1) # right, down, right and down
counts = [[0]*ncols for _ in range(nrows)]
for i in reversed(range(nrows)): # for each row
assert len(mat[i]) == ncols # matrix must be rectangular
for j in reversed(range(ncols)): # for each element in the row
if mat[i][j] != taken:
if i < (nrows - 1) and j < (ncols - 1):
add=1+min(counts[i+x][j+y] for x,y in (dirs))
else:
add=1 # edges
counts[i][j]=add
for line in counts: print(line)
return max(c for rows in counts for c in rows) # max X (or Y) number elements
table=[[c for c in s.strip()] for s in st.splitlines()]
print (max_size(table,'#')**2)
Note that this function starts in the lower right corner and works backwards to the upper left corner and keeps a running total of the max square that could be at the vertex:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 4, 3, 2, 1, 0]
[0, 0, 2, 1, 0, 4, 3, 2, 1, 0]
[0, 0, 2, 1, 0, 4, 3, 2, 1, 0]
[0, 0, 2, 1, 0, 3, 3, 2, 1, 0]
[0, 0, 1, 1, 0, 2, 2, 2, 1, 0]
[0, 0, 0, 0, 0, 1, 1, 1, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 1, 1, 1, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Then square the return for the answer of 16 (4x4). You can see that it would trivial to figure where each square would fit in this matrix; every one is calculated in counts
and you would just add a tuple of (i,j)
to the matrix counts
or another one.
Upvotes: 1
Reputation: 27210
This is quite a classic problem, which is nicely solved in the Dr. Dobb's Journal. Your available squares is just the true valued squares in the article.
Upvotes: 1