【问题标题】:how can solve this problem with dynamic programming?如何用动态规划解决这个问题?
【发布时间】:2019-05-10 09:52:03
【问题描述】:

说明:老鼠可以向上或向右移动

输入

  • 第一行包含桌子大小 n 的数量和奶酪的数量 m。
  • 从下一行开始,给出奶酪的 x、y 位置

输出:

  • 最多吃多少奶酪

示例 1:

  • 输入:1 1 1
  • 输出:1 1

示例 2:

  • 输入:
3 2
1 2
3 1
  • 输出:1

示例 3:

  • 输入:
5 5
2 3
3 2
4 3
4 5
5 2
  • 输出:3

如何用 python 解决? 我试过了

def maxAverageOfPath(table, N): 
    dp = [[0 for i in range(N)] for j in range(N)] 
    dp[0][0] = table[0][0] 
    # Initialize first column of total table(dp) array 
    for i in range(0, N): 
        dp[i][0] = 0


    for j in range(0, N): 
        dp[0][j] = 0

    for i in range(0, N): 
        for j in range(0, N):
            print(i, j)
            if i == N-1 and j == N-1:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
                continue
            if i == N-1 :
                dp[i][j] = table[i][j + 1]
                continue

            if j == N-1 :
                dp[i][j] = table[i + 1][j]
                continue
            dp[i][j] = max(table[i + 1][j], table[i][j + 1])

    return dp

但是失败了……

【问题讨论】:

  • 嗨。就目前而言,您的问题对我来说很难理解。这部分是由于格式化(尝试更好地格式化输入/输出字段和值),部分是由于问题描述本身。程序应该做什么?有什么限制?最后,尝试评论您的代码,以帮助那些试图帮助您更快理解它的人。它还将帮助他们了解您对代码应该做什么/应该做什么做出错误的假设。
  • 使用 bfs 或 dfs 来解决您的问题,从初始点开始,检查左右,如果国际象棋存在将该点存储在该节点中,然后再次按照过程直到到达顶行或超过边界编码,并得到每个 bfs 分支c 中奶酪的总数,最多一个将是答案
  • 在动态编程中,您应该从头到尾遍历解决方案,而不是像现在这样从头到尾遍历。这样一来,您始终可以获得所有必需的信息。
  • @VincentvanderWeele,DP 中两种方法都很好。是否使用自上而下或自下而上的方法取决于您。有时这也是一个特定的问题。根据问题陈述,这里自下而上的方法看起来很合适。
  • @DevkinandanChauhan 确实如此,但是您需要记住记住子结果。我认为自下而上更容易掌握,因为你可以从迭代顺序中“免费”获得记忆。

标签: python algorithm dynamic-programming


【解决方案1】:

对于动态编程,您需要一个边缘条件和一种在您现在所处的位置得分的方法。在那之后,它或多或少是聪明的蛮力。聪明的部分来自记忆,所以你不会重复工作。

下面是 python 的基本递归方法,它执行以下操作:

  • 将奶酪表组织为一组冷冻元组。这可以进行哈希处理以供记忆,并且您可以在恒定时间内确定集合中的位置。

  • 为结束创建一个边缘条件(当两个坐标都是 N 时)和一个当您离开地图时的边缘条件 - 只返回 0。

  • 使用lru_cache 来记忆。您可以自己轻松实现。


from functools import lru_cache

def hasCheese(table, location):
    ''' Helper function just to improve readability '''
    return 1 if location in table else 0

@lru_cache()
def maxC(table, N, location = (0, 0)):  

    # edge conditions final square and off the grid:  
    if location[0] == N and location[1] == N:
        return hasCheese(table, location)
    if any(l > N for l in location):
        return 0

    # recursion
    score_here = hasCheese(table, location)
    return max(score_here + maxC(table, N, (location[0] + 1, location[1])),
               score_here + maxC(table, N, (location[0], location[1] + 1))
              )

t = frozenset([(2, 3), (3, 2), (4, 3), (4, 5), (5, 2)])
N = 5

print(maxC(t, N))
# prints 3

如果您想使用矩阵以自上而下的方式执行此操作,则需要非常小心,您始终拥有先前的索引集。这样做更容易出错,因为您需要获得正确的索引和顺序。当您将其设置为两个嵌套递增循环时,这意味着下一个值始终是当前单元格加上两个单元格的最大值减去一个单位 - 您应该始终在矩阵中向后看。当您期待此内容时,尚不清楚您正在尝试做什么:

 dp[i][j] = table[i][j + 1]

因为j+1尚未确定。

由于奶酪坐标是 1 索引的,一个简单的方法是让您的矩阵索引为零并且大小为 N+1。然后,当您在 1 开始 for 循环时,您始终可以查看并查看较低的索引,而不会低于矩阵,并避免大量 if/else 逻辑。例如:

def hasCheese(table, location):
    ''' Helper function just to improve readability '''
    return 1 if location in table else 0

def maxAverageOfPath(table, N): 
    # matrix is sized one unit bigger
    dp = [[0 for i in range(N+1)] for j in range(N+1)] 

    # iterate 1-5 inclusive
    for i in range(1, N+1): 
        for j in range(1, N+1):
            # because the zeroth row and column are already zero, this works without undershooting the table
            dp[i][j] = hasCheese(table, (i, j)) + max(dp[i][j-1], dp[i-1][j])
    # solution is in the corner
    return dp[N][N]

t = {(2, 3), (3, 2), (4, 3), (4, 5), (5, 2)}
N  = 5

print(maxAverageOfPath(t, N)) #3

完成后,您的矩阵将如下所示:

[0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 1, 1]
[0, 0, 1, 1, 1, 1]
[0, 0, 1, 2, 2, 3]
[0, 0, 2, 2, 2, 3]

你的起点是从右上角开始的 (1, 1),你的答案是左下角。

【讨论】:

  • 我觉得这个答案通过忽略 OP 的矩阵公式来回避这个问题。
  • @Richard,问题是“我如何用 python 解决?”不是“如何用矩阵解决这个问题”。他们尝试了矩阵解决方案,但给他们带来了麻烦。递归 DP 解决方案更易于实现、更易于阅读且不易出错。这使它成为“我如何用 python 解决”的一个很好的答案,当然不值得投反对票。
  • @Richard 单词“matrix”似乎在此页面上仅被引用了 3 次,均在此页面上方的两个 cmets 中。你在说什么?
  • @גלעדברקן Richard 指的是原始帖子中的 dp。它是一个矩阵,在您进行迭代时跟踪值。这是解决动态规划问题的另一种方法。
  • 那又怎样? Op 没有说过要“坚持”这种方法。
【解决方案2】:

在每个点上,您都有两个进一步的选择:

  1. 数组[行] [col+1]
  2. 数组 [row+1] [col]

因为我们必须找出一条涉及最大奶酪的路径。 可以通过像下面这样重复数组来解决相同的问题:

解决方案 =>

array [i] [j] + Max(Recur(array [i] [j+1]), Recur(array [i+1] [j]));

【讨论】:

  • Max(array[i][j] + Recur(array[i][j+1]), array[i][j] + Recur(array[i+1][j])); - 似乎更正确
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-25
  • 1970-01-01
  • 1970-01-01
  • 2011-07-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多