在这个算法中实现动态编程?

时间:2014-12-23 17:34:28

标签: python algorithm recursion dynamic-programming memoization

我获得了一个可以帮助我解决以下问题的算法:

选择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]让我感到沮丧,因为xy每个值都会改变所以我会只需将之前的金额提交到备忘录中,但我无法完全理解这一点。

对于正确方向的任何指导表示赞赏,谢谢。

1 个答案:

答案 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