我有一个问题,我必须在n * n网格中找到最大的正方形。 e.g。
. . . . . . # . # . . # . . . . # . # . . # . . .
最大的方块在底角是3乘3。 我应该在返回之前返回有人可以采取的最多步骤,这样他们就可以无限地重复这个步骤,而不会撞到墙“#”或走出n * n方形,这就是为什么输出比宽度/长度小一个的原因。广场。
我的代码从左到右,从上到下遍历网格,寻找面向下和向右的顶点。一旦找到它,然后找到面向上和向右的最大可能顶点,当它发现检查所有四个边以查看它们是否被组成或.
时。在n = 100左右的任何事情上,这个代码在1秒内工作,但是我需要它在1秒内运行n = 500.有关如何加快速度的提示吗?
import sys
input = sys.stdin.readline
n = int(input())
maze = [list(input()) for _ in range(n)]
squares = 0
for r in range(n - 1):
for c in range(n - 1):
if maze[r][c] == '.' and maze[r][c + 1] == '.' and maze[r + 1] [c] == '.':
sides = []
for i in range(min(n - r - 1, n - c - 1), -1, -1):
if maze[r + i][c + i] == '.' and maze[r + i][c + i - 1] == '.' and maze[r + i - 1][c + i] == '.':
sides = i
if maze[r][c : c + sides] == ['.'] * sides and maze[r + sides][c : c + sides] == ['.'] * sides:
a = True
for j in range(sides):
if maze[r + j][c] != '.' or maze[r + j][c + sides] != '.':
a = False
if a and sides > squares:
squares = sides
break
if squares == n - 1:
break
print(squares)
答案 0 :(得分:2)
我可以想到O(n^3)
算法如下:
top[][], bottom[][], left[][], right[][]
,每个数组都存储了(i,j)
(i,j)
,将其用作方形的左下角,对于每个对角点(i-1, j+1), (i-2, j+2)
...等,测试这些点是否可以用作方形& #39; s右上角。存储过程中的最大方形边对于步骤1,可以在O(n^2)
对于第2步,当我们遍历所有(i,j)
时,对于每个(i,j)
,我们必须至多看到所有对角点最多n
,我们得到的总数O(n^3)
步骤2中的测试可以使用4个预先计算的阵列在O(1)
中完成,只需检查"可能的正方形"的四个角。可以通过检查相应的方向(顶部,底部,左侧,右侧)来加入
当然,有许多小事可以加快,例如:
在第2步中,对于每个(i,j)
,仅检查范围为[current_maximum_diagonal_found ... max(right[i][j], top[i][j])]
沿整个算法更新current_maximum_diagonal_found
,以便我们希望有一些(i,j)
,我们无需检查整个n
对角点。
但严格来说,它仍然是O(n^3)
,但就我所知,它应该可以在1秒内运行n~500
答案 1 :(得分:1)
O(n^3)
的实现。我对代码进行了评论,以便您可以按照这个想法进行操作。仍然有提高速度的空间,但这个版本已经完成了工作(例如迷宫尺寸为500x500):
Finished after 0.708 seconds.
Result: 112581 squares found, maximum square (x=13, y=270, size=18).
这是源代码(Python 3):
import random
import pprint
import time
# small sample maze
maze = ['.....',
'...#.',
'.#...',
'.#.#.',
'.#...']
# convert to boolean maze
maze_bin = [[True if cell == '.' else False for cell in line] for line in maze]
# uncomment to generate a random maze
# maze_size = 500
# threshold = 0.2
# maze_bin = [[1 if random.random() >= threshold else 0 for _ in range(maze_size)] for _ in range(maze_size)]
# take start time
t1 = time.time()
# rotate the maze (first column becomes first row, first row becomes first column)
maze_bin_rot = [[maze_bin[i][j] for i in range(len(maze_bin))] for j in range(len(maze_bin[0]))]
# horizontal_lengths is a two-dimensional list that contains the number of possible steps to the right for every cell.
horizontal_lengths = []
for line in maze_bin:
num = 0
line_lengths = []
for i in reversed(line):
line_lengths.append(i*num)
num = i * (num + i)
horizontal_lengths.append(tuple(reversed(line_lengths)))
# vertical_lengths is a two-dimensional list that contains the number of possible steps to the bottom for every cell.
vertical_lengths_rot = []
for line in maze_bin_rot:
num = 0
line_lengths = []
for i in reversed(line):
line_lengths.append(i*num)
num = i * (num + i)
vertical_lengths_rot.append(tuple(reversed(line_lengths)))
# do the rotation again to be back in normal coordinates
vertical_lengths = [[vertical_lengths_rot[i][j] for i in range(len(vertical_lengths_rot))] for j in range(len(vertical_lengths_rot[0]))]
# calculate the maximum size of a square that has it's upper left corner at (x, y).
# this is the minimum of the possible steps to the right and to the bottom.
max_possible_square = []
for y in range(len(maze_bin)):
line = []
for x in range(len(maze_bin[0])):
line.append(min(horizontal_lengths[y][x], vertical_lengths[y][x]))
max_possible_square.append(line)
# search for squares
results = []
max_size_square = (-1, -1, -1)
for y in range(len(max_possible_square)):
for x in range(len(max_possible_square[0])):
# start with maximum possible size and decrease size until a square is found.
for size in reversed(range(1, max_possible_square[y][x]+1)):
# look at the upper right (x+size,y) and bottom left corner (x,y+size).
# if it's possible to make at least size steps to the right from the bottom left corner
# and at least size steps to the bottom from the upper right corner, this is a valid square.
if horizontal_lengths[y+size][x] >= size and vertical_lengths[y][x+size] >= size:
results.append((x, y, size+1))
if size+1 > max_size_square[2]:
max_size_square = (x, y, size+1)
# break after the the largest square with upper left corner (x,y) has been found.
break
t2 = time.time()
# comment this print section if you use larger grids
print('Maze:')
pprint.pprint(maze_bin)
print('\n')
print('Horizontal possible steps:')
pprint.pprint(horizontal_lengths)
print('\n')
print('Vertical possible steps:')
pprint.pprint(vertical_lengths)
print('\n')
print('Maximum possible size of square:')
pprint.pprint(max_possible_square)
print('\n')
print('Results:')
for square in results:
print('Square: x={}, y={}, size={}'.format(*square))
print('\n')
# final results
print('Finished after {:.3f} seconds.'.format(t2-t1))
print('Result: {} squares found, maximum square (x={}, y={}, size={}).'.format(len(results), *max_size_square))
我希望这就是你要找的东西。如果您有任何疑问,请在下面留言;)
答案 2 :(得分:0)
如果我们不想列举所有结果,可能值得考虑的一个优化如下。这是基于策略 - “如果不能导致最佳解决方案,请不要继续使用此单元格”
for y in range(possible_y_value):
for x in range(possible_x_value):
# We are ready to process cell identified by (x,y).
# Check if max_possible_square_length at this cell is greater than size of best_result seen so far. If so, proceed further, otherwise skip this cell
if max_possible_square[y][x]+1 > best_result.size:
# proceed further with the inner most for loop
....
即使是在最内部的for循环中,当它低于目前为止看到的best_result的大小时,我们可以在迭代时突破循环