动态编程 - 带倍增器的电路板

时间:2017-12-19 21:33:25

标签: algorithm dynamic-programming

我得到了相当标准的DP问题 - 使用整数来n x n,这些都是正面的。我想在第一行的某个地方开始,在最后一行的某个地方结束并尽可能多地积累总和。从字段(i,j)开始,我可以转到字段(i+1, j-1)(i+1, j)(i+1, j+1)。 这是相当标准的DP问题。但是我们添加了一件事 - 字段上可以有一个星号,而不是数字。如果我们遇到星号,那么我们得到了0分,但我们将乘数增加1。我们在遍历期间收集的所有数字都乘以multiplier。 我不知道如何用这个乘数来解决这个问题。我认为这仍然是一个DP问题 - 但如何使方程式适合它呢?

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

你仍然可以使用DP,但你必须跟踪两个值:" base"价值,即没有任何乘数应用于它,"有效"值,即乘数。你通过网格向后工作,从前一行开始,得到三个"相邻"之后的行中的单元格(可能的"下一个"路径上的单元格),然后选择具有最高值的单元格。

如果当前单元格为*,则会获得base + effective最大的单元格,否则您只会获得effective得分最高的单元格。

这是Python中的一个示例实现。请注意,我不是*而是仅使用0作为乘数,而是按顺序循环网格而不是反向,只是因为它更方便。

import random

size = 5
grid = [[random.randint(0, 5) for _ in range(size)] for _ in range(size)]
print(*grid, sep="\n")

# first value is base score, second is effective score (with multiplier)
solution = [[(x, x) for x in row] for row in grid]

for i in range(1, size):
    for k in range(size):
        # the 2 or 3 values in the previous line
        prev_values = solution[i-1][max(0, k-1):k+2]
        val = grid[i][k]
        if val == 0:
            # multiply
            base, mult = max(prev_values, key=lambda t: t[0] + t[1])
            solution[i][k] = (base, base + mult)
        else:
            # add
            base, mult = max(prev_values, key=lambda t: t[1])
            solution[i][k] = (val + base, val + mult)

print(*solution, sep="\n")
print(max(solution[-1], key=lambda t: t[1]))

示例:随机5x5网格,0对应*

[4, 4, 1, 2, 1]
[2, 0, 3, 2, 0]
[5, 1, 3, 4, 5]
[0, 0, 2, 4, 1]
[1, 0, 5, 2, 0]

具有基值和有效值的最终solution网格:

[( 4,  4), ( 4,  4), ( 1,  1), ( 2,  2), ( 1,  1)]
[( 6,  6), ( 4,  8), ( 7,  7), ( 4,  4), ( 2,  4)]
[( 9, 13), ( 5,  9), ( 7, 11), (11, 11), ( 9,  9)]
[( 9, 22), ( 9, 22), ( 9, 13), (11, 15), (12, 12)]
[(10, 23), ( 9, 31), (14, 27), (13, 17), (11, 26)]

因此,此网格的最佳解决方案是来自31的{​​{1}}。通过网格(9, 31)网格向后工作,这对应于路径solution,即0-0-5-0-4,因为3*5 + 4*4 = 31之前有2 *,而5*之前{1}}。