Matrix-Brute Force中的最小路径和

时间:2017-02-22 00:10:37

标签: ruby algorithm recursion matrix

我正在解决以下问题:

  

给定m x n网格填充非负数,找到从左上角到右下角的路径,最小化沿其路径的所有数字的总和。    注意:您只能在任何时间向下或向右移动。

我最初的印象是,从网格中的每个位置开始,向右移动到向下移动的最小长度。但是,这给了我以下错误答案:

Input:
[[1,2],[1,1]]
Output:
2
Expected:
3

直观地,不确定我做错了什么。它也是非常简单的代码(我知道它没有被记忆 - 正在计划下一步)但直觉上不确定出了什么问题。递归基本情况是有意义的,并且正在考虑每个数字。

def min_path_sum(grid)
    smallest_path(0, 0, grid)
end

def smallest_path(row, col, grid)
    return 0 if (row == grid.length || col == grid.first.length)
    current_val = grid[row][col]
    [current_val + smallest_path(row+1, col, grid), current_val + smallest_path(row, col+1, grid)].min #memoize here

end

2 个答案:

答案 0 :(得分:0)

你没有做出正确的终止条件。只检查 右列或底行。你需要保持在界限范围内,但要继续直到你到达右下角。你需要在界限内重复,直到你达到两个限制。

鉴于此,您的代码可以正常工作:它找到2到底行的路径,而不是3到右边缘的路径。你只需要教它完成这项工作。

这足以让你找到解决方案吗?

答案 1 :(得分:0)

由于这是非循环有向图上的最短路径问题,您可以使用标准shortest path algorithm

您还可以使用动态编程(" DP),这可能是最有效的优化技术。我的回答实现了DP算法。

最短路径或DP算法远远优于枚举从左上角到右下角的所有路径。随着路径数量随着数组的大小呈指数增长,简单的枚举只能用于中等大小的数组。

DP算法的思想如下。让nm分别为行数和列数。首先计算从最后一行中的每列到最后一行中最后一列的最短路径。这是一个简单的计算,因为每个元素只有一条到[m-1, n-1]的路径。从[m-1, n-2]开始,我们只需返回[m-1, 0]

接下来,我们计算从其他每一行中的每个元素到[m-1, n-1]的最短路径,从倒数第二行(m-2)开始,然后回到第一行(0 )。每行中的最后一个元素[i, n-1]是一个简单的计算,因为只能向下(到[i+1, n-1])。因此,从[i, n-1][m-1, n-1]的最短路径首先转到[i+1, n-1],然后沿着我们已经计算过的[i+1, n-1]的最短路径(包括它长度,当然)。从[i, n-1]开始的最短路径的长度是" down" [i, n-1]的距离加上[i+1, n-1]的最短路径的长度。

对于元素[i, j],n-1 , i&lt; j < m-1,如果我们向右和向下移动,我们会计算最短路径,并选择两者中较短的路径。

我们可以按如下方式实现。

<强>代码

def shortest_path(distance)
  last_row, last_col = distance.size-1, distance.first.size-1
  h = {}
  last_row.downto(0) do |i|
    last_col.downto(0) do |j|
       h_right = { min_path_len: distance[i][j][:r] + h[[i,j+1]][:min_path_len],
                   next_node: [i,j+1] } if j < last_col
       h_down  = { min_path_len: distance[i][j][:d] + h[[i+1,j]][:min_path_len],
                   next_node: [i+1,j] } if i < last_row
       g =
       case
       when i == last_row && j == last_col  
         { min_path_len: 0, next_node: nil }
       when i == last_row
         h_right
       when j == last_col
         h_down
       else
         [h_right, h_down].min_by { |f| f[:min_path_len] }
       end
       h[[i,j]] = g
    end
  end
  build_path(h)
end

def build_path(h)
  node = [0, 0]
  len = h[node][:min_path_len]
  arr = []
  while h[node][:next_node]
    arr << node
    node = h[node][:next_node]
  end
  [len, arr]
end

示例

假设这些是相邻节点之间的距离。

● 4 ● 3 ● 1 ● 2 ●
6   2   5   4   5
● 3 ● 4 ● 6 ● 3 ●
1   3   4   2   3
● 6 ● 3 ● 1 ● 2 ●

以哈希数组的形式提供这些信息很方便。

distance = [
  [{ r: 4, d: 6 }, { r: 3, d: 2 }, { r: 1, d: 5 }, { r: 2, d: 4 }, { d: 5 }],
  [{ r: 3, d: 1 }, { r: 4, d: 3 }, { r: 6, d: 4 }, { r: 3, d: 2 }, { d: 3 }],
  [{ r: 6  },      { r: 3 },       { r: 1 },       { r: 2 }]
]

我们现在可以计算最短路径。

p shortest_path distance 
  #=> [15, [[0, 0], [0, 1], [1, 1], [2, 1], [2, 2], [2, 3]]]

返回的数组的第二个元素给出了最短路径。 15是该路径的长度。