如何通过动态编程解决此问题?

时间:2019-05-10 09:52:03

标签: python algorithm dynamic-programming

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

输入

  • 第一行包含表格大小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

但失败了...

2 个答案:

答案 0 :(得分:2)

对于动态编程,您需要一个边缘条件以及一种对当前位置进行评分的方法。之后,它或多或少是聪明的蛮力。聪明的部分来自于记忆,因此您无需重复工作。

这是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),答案是左下角。

答案 1 :(得分:1)

在每个点上,您都有两个选择可以继续:

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

因为我们必须找到一条涉及最大奶酪的道路。 可以通过重复遍历如下数组来解决此问题:

解决方案=>

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