从暴力递归到一维动态规划

刚开始写动态规划时,看到答案提供的一维数组的解法是不是很懵?一杯茶,一包烟,一道dp答案看一天?其实,直接研究示例代码对小白很不友好的,如何正确解决动态规划问题呢?这还得一步一步,从最简单的暴力递归开始:

  • 暴力递归(回溯法或DFS

    • 这是最直接的方法,通过深度优先搜索(DFS)来探索所有可能的解决方案,直到找到满足条件的解。这种方法通常效率低下,因为它会重复计算很多子问题。
    • 以背包问题举例:
    • 给定n个物品和一个容量为W的背包,每个物品有重量w[i]和价值v[i],求这些物品能装入背包的最大价值。
    • def knapsack_recursive(W, wt, val, n):
          if n == 0 or W == 0:
              return 0
          if wt[n-1] > W:
              return knapsack_recursive(W, wt, val, n-1)
          else:
              return max(val[n-1] + knapsack_recursive(W-wt[n-1], wt, val, n-1),
                         knapsack_recursive(W, wt, val, n-1))
      
      
  • 记忆法优化(Top-down思路)

    • 在暴力递归的基础上,通过使用一个数组(通常是二维数组dp[][])来存储已经计算过的子问题的结果,避免重复计算。这种方法称为记忆化搜索,它是一种自顶向下的动态规划方法。
    • def knapsack_memo(W, wt, val, n, memo=None):
          if memo is None:
              memo = {}
          if (W, n) in memo:
              return memo[(W, n)]
          if n == 0 or W == 0:
              return 0
          if wt[n-1] > W:
              memo[(W, n)] = knapsack_memo(W, wt, val, n-1, memo)
          else:
              memo[(W, n)] = max(val[n-1] + knapsack_memo(W-wt[n-1], wt, val, n-1, memo),
                                 knapsack_memo(W, wt, val, n-1, memo))
          return memo[(W, n)]

  • 从大到小的Top-down思路

    • 这指的是在解决子问题时,从较大的问题逐步分解到较小的问题,并在这个过程中使用记忆化的结果。
  • Buttom-up的填充dp数组

    • 这是一种自底向上的动态规划方法。它从最简单的子问题开始解决,逐步构建出更大问题的解。在这个过程中,dp数组会被逐步填充,每个位置存储的是对应子问题的最优解。
    • def knapsack_bottom_up(W, wt, val, n):
          dp = [[0 for x in range(W+1)] for x in range(n+1)]
          
          for i in range(n+1):
              for w in range(W+1):
                  if i == 0 or w == 0:
                      dp[i][w] = 0
                  elif wt[i-1] <= w:
                      dp[i][w] = max(val[i-1] + dp[i-1][w-wt[i-1]], dp[i-1][w])
                  else:
                      dp[i][w] = dp[i-1][w]
                      
          return dp[n][W]
  • 将二维数组优化成一维数组

    • 在某些动态规划问题中,二维dp数组可以通过观察状态转移方程来优化成一维数组,从而减少空间复杂度。
    • def knapsack_bottom_up_optimized(W, wt, val, n):
          dp = [0] * (W+1)
          
          for i in range(n):
              for w in range(W, wt[i]-1, -1):
                  dp[w] = max(dp[w], val[i] + dp[w-wt[i]])
                      
          return dp[W]

      这一般是示例代码了,它是经过多次优化后最终呈现出来的,简洁美观效率高,对动态规划没有深厚理解很难看懂,那么如何建立深厚理解呢,一定的学习顺序可以帮助你系统地掌握动态规划,从简单到复杂,逐步深化理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值