我获得了一个可以帮助我解决以下问题的算法:
选择NxN
网格。从左上角开始,仅从每个节点向下或向右移动到右下角。例如:
grid = [[0,2,5],[1,1,3],[2,1,1]]
将此列表想象为网格:
0 2 5
1 1 3
2 1 1
您访问的每个号码都必须添加到运行总计中。在这种情况下,有六种不同的方式可以到达底部,为您提供总和。我给出的算法可以用于此并返回可能的总和列表如下:
def gridsums(grid, x, y, memo):
if memo[x][y] is not None:
return memo[x][y]
if x == 0 and y == 0:
sums = [0]
elif x == 0:
sums = gridsums(grid, x, y-1, memo)
elif y == 0:
sums = gridsums(grid, x-1, y, memo)
else:
sums = gridsums(grid, x-1, y, memo) + gridsums(grid, x, y-1, memo)
sums = [grid[x][y] + s for s in sums]
memo[x][y] = sums
return sums
def gridsumsfast(grid):
memo = []
for row in grid:
memo.append([])
for cell in row:
memo[-1].append(None)
return gridsums(grid, len(grid[0]) - 1, len(grid) - 1, memo)
缩进不正确但你明白了。然而,这适用于N的更大值,它根本不起作用。例如,最多N值为20,需要很长时间,在某些测试中,我会将其运行一次。
显然主要功能正在进行大量的重复工作,那么我究竟能用这种算法实现记忆/动态编程呢?这项工作重复了很多次,让我有理由说动态编程需要实施,但行sum = [grid[x][y] = s for s in sums]
让我感到沮丧,因为x
和y
每个值都会改变所以我会只需将之前的金额提交到备忘录中,但我无法完全理解这一点。
对于正确方向的任何指导表示赞赏,谢谢。
答案 0 :(得分:1)
所有路径都从上方或左侧到达单元格。如果从左到右和从上到下遍历网格,则可以累计已经计算过的单元格的总和。这个想法与TravisJ's answer中的想法相同。
def gridsums(grid):
previous_row_sums = [set() for _ in grid[0]]
previous_row_sums[0].add(0) #seed
for row in grid:
left_sums = set()
row_sums = []
for value, above_sums in zip(row, previous_row_sums):
old_sums = left_sums | above_sums
sums = {value + old for old in old_sums}
row_sums.append(sums)
left_sums = sums
previous_row_sums = row_sums
return sums