简体   繁体   English

给定起点的矩阵中的最大和路径

[英]Maximum sum path in the matrix with a given starting point

I am learning to tackle a similar type of dynamic programming problem to find a maximum path sum in a matrix.我正在学习解决类似类型的动态规划问题,以在矩阵中找到最大路径和。

I have based my learning on this algorithm on the website below.我的学习基于以下网站上的此算法。

Source: Maximum path sum in matrix来源:矩阵中的最大路径和

The problem I am trying to solve is a little bit different from the one on the website.我试图解决的问题与网站上的问题有点不同。

The algorithm from the website makes use of max() to update values in the matrix to find max values to create a max path.该网站的算法利用max()更新矩阵中的值以找到最大值以创建最大路径。

For example, given an array:例如,给定一个数组:

sample = [[110, 111, 108, 1],
          [9, 8, 7, 2],
          [4, 5, 10, 300],
          [1, 2, 3, 4]]

The best sum path is 111 + 7 + 300 + 4 = 422最佳求和路径是 111 + 7 + 300 + 4 = 422

In the example above, the algorithm finds the first path by finding what is the max value of the first row of the matrix.在上面的示例中,算法通过查找矩阵第一行的最大值来找到第一条路径。

My question is, what if have to specify the starting point of the algorithm.我的问题是,如果必须指定算法的起点怎么办。 The value h is given as the first element to start.值 h 作为开始的第一个元素给出。

For example, given the sample array above, if h = 0, we need to start at sample[0][h], therefore the best path would be例如,给定上面的样本数组,如果 h = 0,我们需要从 sample[0][h] 开始,因此最佳路径是

110 (Our staring point) + 8 + 10 + 4 = 132 110(我们的起点)+ 8 + 10 + 4 = 132

As you can see, the path can only travel downwards or adjacent, therefore if we start at h = 0, there will be values that we cannot reach some values such as 300.如您所见,路径只能向下或相邻,因此如果我们从 h = 0 开始,将会有一些我们无法达到的值,例如 300。

Here is my messy attempt of solving this within the O(N*D) complexity,这是我在 O(N*D) 复杂度内解决这个问题的混乱尝试,

# Find max path given h as a starting point
def find_max_path_w_start(mat, h):
    res = mat[0][0]
    M = len(mat[0])
    N = len((mat))

    for i in range(1, N):
        res = 0
        for j in range(M):
            # Compute the ajacent sum of the ajacent values from h
            if i == 1:
                # If h is starting area, then compute the sum, find the max
                if j == h:
                    # All possible
                    if (h > 0 and h < M - 1):
                        mat[1][h + 1] += mat[0][h]
                        mat[1][h] += mat[0][h]
                        mat[1][h - 1] += mat[0][h]
                        print(mat)
                    # Diagona Right not possible
                    elif (h > 0):
                        mat[1][h] += mat[0][h]
                        mat[1][h - 1] += mat[0][h]
                    # Diagonal left not possible
                    elif (h < M - 1):
                        mat[1][h] += mat[0][h]
                        mat[1][h + 1] += mat[0][h]
                # Ignore value that has been filled.
                elif j == h + 1 or j == h - 1 :
                    pass
                # Other elements that cannot reach, make it -1
                elif j > h + 1 or j < h - 1:
                    mat[i][j] = -1
            else:
                # Other elements that cannot reach, make it -1
                if j > h + 1 or j < h - 1:
                    mat[i][j] = -1
                else:
                    # When all paths are possible
                    if (j > 0 and j < M - 1):
                        mat[i][j] += max(mat[i - 1][j],
                                         max(mat[i - 1][j - 1],
                                             mat[i - 1][j + 1]))
                    # When diagonal right is not possible
                    elif (j > 0):
                        mat[i][j] += max(mat[i - 1][j],
                                         mat[i - 1][j - 1])
                    # When diagonal left is not possible
                    elif (j < M - 1):
                        mat[i][j] += max(mat[i - 1][j],
                                         mat[i - 1][j + 1])

            res = max(mat[i][j], res)

    return res

My approach is to only store the reachable values, if example if we start at h = 0, since we are starting at mat[0][h] , we can only compute the sum of current and bottom max(mat[1][h] and sum of current and adjacent right mat[1][h + 1]) , for other values I mark it as -1 to mark it as unreachable.我的方法是只存储可达值,如果我们从 h = 0 开始,因为我们从mat[0][h]开始,我们只能计算当前和底部max(mat[1][h]以及当前和相邻右mat[1][h + 1])的总和,对于其他值,我将其标记为 -1 以将其标记为无法访问。

This doesn't return the expected sum at the end.这不会在最后返回预期的总和。

Is my logic incorrect?我的逻辑不正确吗? Are there other values that I need to store to complete this?我需要存储其他值来完成此操作吗?

You can set all elements of the first row except h to negative infinity, and compute the answer as if there is no starting point restriction.您可以将除 h 之外的第一行的所有元素设置为负无穷大,并像没有起点限制一样计算答案。

For example, put this piece of code at the start of your code例如,将这段代码放在代码的开头

for i in range(M):
    if i != h:
        mat[0][i] = -1e100

Here is a solution which works in a similar way to yours, however it only calculates path sums for at matrix values that could have started at h .这是一个与您的工作方式类似的解决方案,但是它只计算可能从h开始的 at 矩阵值的路径总和。

def find_max_path_w_start(mat, h):
    M = len(mat[0])
    N = len((mat))

    for i in range(1, N):
        # `h - i` is the left hand side of a triangle with `h` as the top point.
        # `max(..., 0)` ensures that is is at least 0 and in the matrix.
        min_j = max(h - i, 0)

        # similar to above, but the right hand side of the triangle.
        max_j = min(h + i, M - 1)

        for j in range(min_j, max_j + 1):
            # min_k and max_k are the start and end indices of the points in the above
            # layer which could potentially lead to a correct solution.
            # Generally, you want to iterate from `j - 1` up to `j + 1`,
            # however if at the edge of the triangle, do not take points from outside the triangle:
            # this leads to the `h - i + 1` and `h + i - 1`.
            # The `0` and `M - 1` prevent values outside the matrix being sampled.
            min_k = max(j - 1, h - i + 1, 0)
            max_k = min(j + 1, h + i - 1, M - 1)

            # Find the max of the possible path totals
            mat[i][j] += max(mat[i - 1][k] for k in range(min_k, max_k + 1))
            
    # Only sample from items in the bottom row which could be paths from `h`
    return max(mat[-1][max(h - N, 0):min(h + N, M - 1) + 1])


sample = [[110, 111, 108, 1],
          [9, 8, 7, 2],
          [4, 5, 10, 300],
          [1, 2, 3, 4]]

print(find_max_path_w_start(sample, 0))

It's easy to build a bottom up solution here.在这里构建自下而上的解决方案很容易。 Start thinking the case when there's only one or two rows, and extend it to understand this algorithm easily.开始考虑只有一两行的情况,并对其进行扩展以轻松理解该算法。
Note: this modifies the original matrix instead of creating a new one.注意:这会修改原始矩阵而不是创建新矩阵。 If you need to run the function multiple times on the same matrix, you'll need to create a copy of the matrix to do the same.如果您需要在同一个矩阵上多次运行 function,则需要创建矩阵的副本来执行相同操作。

def find_max_path_w_start(mat, h):
    res = mat[0][0]
    M = len(mat[0])
    N = len((mat))

    # build solution bottom up
    for i in range(N-2,-1,-1):
        for j in range(M):
            possible_values = [mat[i+1][j]]
            if j==0:
                possible_values.append(mat[i+1][j+1])
            elif j==M-1:
                possible_values.append(mat[i+1][j-1])
            else:
                possible_values.append(mat[i+1][j+1])
                possible_values.append(mat[i+1][j-1])
            mat[i][j] += max(possible_values)
    return mat[0][h]

sample = [[110, 111, 108, 1],
          [9, 8, 7, 2],
          [4, 5, 10, 300],
          [1, 2, 3, 4]]

print(find_max_path_w_start(sample, 0)) # prints 132

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM