【问题标题】:Robot in a Grid - how to get all possible paths网格中的机器人 - 如何获得所有可能的路径
【发布时间】:2020-09-30 06:23:49
【问题描述】:

我正在尝试解决这个问题:

有一个包含 r 行和 c 列的网格。坐在左上角单元格中的机器人只能在两个方向上移动,向右和向下。但是必须避开某些细胞,机器人不能踩到它们。从左上角到右下角为机器人找到一条路径。

这个问题特别要求一个单一的路径,这似乎很简单:

网格为boolean[][],我的伪代码是

List<String> path = new ArrayList<String>()
boolean found = false

void getPath(r, c){
    if (!found) {

      if ( (r or c is outofbounds) || (!grid[r][c]) )
          return

      if (r==0 AND c==0)  // we reached
           found = true

      getPath(r-1, c)
      getPath(r, c-1)

      String cell = "(" + r + ", " + c + ")"
      path.add(cell)

    }    
}

虽然我想知道如何获得所有可能的路径(不仅仅是计数,还有路径值)。请注意,它有 r 行和 c 列,因此它不是 nxn 网格。我正在尝试考虑 DP/递归解决方案,但无法提出任何解决方案并卡住了。当递归有两种方式时,很难想象。

任何指针?并且任何关于如何“思考”这些问题的一般帮助将不胜感激:)。

【问题讨论】:

    标签: recursion dynamic-programming


    【解决方案1】:

    有什么建议吗?并且对于如何“思考”这些问题的任何一般帮助将不胜感激:)。

    解决问题的方法:

    1. 心理构建问题的图 G。在这种情况下,顶点是网格中的单元格,并且在存在有效机器人移动的地方创建有向边。
    2. 搜索 G 的属性。在这种情况下,G 是 DAG(有向无环图)。
    3. 使用此类属性来提出解决方案。在这种情况下(G 是一个 DAG),通常使用 拓扑排序动态规划 来查找有效路径的数量。

    实际上您不需要构造图,因为边集非常清晰,或者像通常的矩阵迭代(增量行索引和增量列索引)一样进行拓扑排序是这个隐式图的拓扑排序。

    动态规划部分可以通过在每个单元格[x][y] 中存储从[0][0][x][y] 的有效路径数量并检查下一步要移动到哪里来解决。
    重复:

    计算后,答案存储在dp[n - 1][m - 1] 中,其中n 是行数,m 是列数。总体运行时间为O(nm)

    如何找到所有可能的有效路径:
    通常的回溯是有效的,我们可以通过应用早期修剪来加速它。事实上,如果我们计算dp 矩阵,然后我们从单元格[n - 1][m - 1] 进行回溯,我们可以避免机器人进入dp 值为零的单元格时出现无效路径。

    预先计算出dp矩阵的Python代码:

    n, m = 3, 4
    bad = [[False, False, False, False],
           [ True,  True, False, False],
           [False, False, False, False]]
    dp = [[1, 1, 1, 1], 
          [0, 0, 1, 2], 
          [0, 0, 1, 3]]
    
    paths = []
    curpath = []
    def getPath(r, c):
        if dp[r][c] == 0 or r < 0 or c < 0:
            return
        curpath.append((r, c))
        if r == 0 and c == 0:
            paths.append(list(reversed(curpath)))
        getPath(r - 1, c)
        getPath(r, c - 1)
        curpath.pop()
    
    getPath(n - 1, m - 1)
    print(paths)
    
    # valid paths are [[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3)], 
    #                  [(0, 0), (0, 1), (0, 2), (1, 2), (1, 3), (2, 3)], 
    #                  [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 3)]]
    

    请注意,这与您的代码非常相似,需要将所有有效路径存储在一起,并注意附加列表是 curpath 的副本,以避免以空列表列表结束。

    运行时:O((n + m) * (amount of valid paths)),因为模拟的机器人移动属于有效路径或第一步进入使用前瞻检测到的无效路径 (dp)。警告:此方法是指数型的,因为有效路径的数量可以是。

    【讨论】:

    • 你解释的有道理,可以用来计算总数。路径,但它会返回一个像[[0, 1, 1][1, 2, 3][1, 3, 6]] 这样的矩阵(对于3 行3 列),但是我怎样才能从这个矩阵中推断出实际的路径值?即案例中的6条路径。
    • @Ufder 因为路径的数量最多可以是一次采用 n 的 (n + m) 个元素的组合而不重复,所以迭代所有有效路径时的最佳运行时间是使用 O(1 ) 修剪(无效路径是那些进入 dp 值为零的单元格的路径)。最好从单元格 [n-1][m-1] 开始回溯到 [0][0] 以便在创建无效路径时正确修剪。
    • 再次感谢,但也许我没有说清楚。我确实在回溯,从最后一个单元格开始,到 (0,0) 结束,即进行自下而上的递归。我能够得到很好的计数。但我不清楚如何获得实际路径,例如。 [[(0, 0), (0, 1), (1, 1), (1, 2), (2, 2)], [(0, 0), (0, 1), (1, 1), (2,1), (2, 2)]] 例如,有 2 条路径包含从头到尾的单元格地址。这就是我要找的。​​span>
    • @Ufder 我编辑了答案以适合您的整个问题:-)
    • 哇,非常感谢,非常感谢!让我花点时间尝试理解这一点,然后接受答案!
    猜你喜欢
    • 1970-01-01
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    相关资源
    最近更新 更多