<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          八十九、動態(tài)規(guī)劃系列背包問題之完全背包

          共 8645字,需瀏覽 18分鐘

           ·

          2021-03-14 15:47


          「@Author:Runsen」

          動態(tài)規(guī)劃需要搞定三個系列:三個背包,零錢問題和股票問題。今天就開始干掉三個背包問題。

          三個背包問題:01背包,多重背包,完全背包。上次搞定了01背包,那么繼續(xù)學習完全背包。

          我們有種物品,物品的重量為,價格為。我們假定所有物品的重量和價格都是非負的,背包所能承受的最大重量W,每種物品都有無限件可用,則該問題成為完全背包問題 。

          題目來源:https://www.acwing.com/problem/content/description/3/

          先上代碼,和01背包問題的解法有略微的改動,區(qū)別在于「遍歷體積時從逆序改為順序」,就只有這一個不同,在上一篇博客中有關于01背包問題的理解。

          # 代碼基本一樣
          n, v = map(int, input().split())
          goods = []
          for i in range(n):
              goods.append([int(i) for i in input().split()])
          dp = [0 for i in range(v+1)]
          for i in range(n):
              for j in range(v+1): # 從前往后
                  if j >= goods[i][0]:
                      dp[j] = max(dp[j], dp[j-goods[i][0]]+goods[i][1])
          print(dp[-1])

          # 測試代碼
          5 10
          1 2
          2 3
          3 4
          4 5
          5 6
          20

          下面是有關完全背包的題目

          Leetcode 279. 完全平方數(shù)

          給定正整數(shù) n,找到若干個完全平方數(shù)(比如 14916, ...)使得它們的和等于 n。你需要讓組成和的完全平方數(shù)的個數(shù)最少。

          示例 1:

          輸入: n = 12
          輸出: 3 
          解釋: 12 = 4 + 4 + 4.
          示例 2:

          輸入: n = 13
          輸出: 2
          解釋: 13 = 4 + 9

          首先,明確dp,然后找dp的轉(zhuǎn)移方程。

          這里,dp[i]:表示完全平方數(shù)和為i的 最小個數(shù)。這個是沒有任何問題的,關鍵是dp的轉(zhuǎn)移方程。

          對于Runsen這個菜鳥來說,也很快指的這是轉(zhuǎn)移方程,就是i減去k 加上1。本質(zhì)上就是斐波那契數(shù)列的一個變形。

          「問題就轉(zhuǎn)為了求n的最大平方和的序列。」

          i = 1
          nums = []
          while i*i <= n:
           nums.append(i*i)
           i = i + 1

          然后就是完全背包的反例的問題了。那么這個動態(tài)規(guī)劃的問題基本解決了。

          n = int(input())
          i = 1
          nums = []
          while i*i <= n:
              nums.append(i*i)
              i = i + 1
          print(nums)
          # dp = [0] * (n+1) 是求最大值,[float('inf')] * (n+1)求最小值
          # 如果寫成 dp = [0] * (n+1) ,那么永遠0最小
          dp = [float('inf')] * (n+1)
          dp[0] = 0
          for i in range(1,n+1):
              # j 是平方數(shù)
              for j in nums:
                  if i<j:
                      break
                  dp[i] = min(dp[i], dp[i - j] + 1)
          print(dp[-1])

          下面代碼來源官方的動態(tài)規(guī)劃,和Runsen的基本一樣。

          import math
          def numSquares(n):
              """
              :type n: int
              :rtype: int
              """

              square_nums = [i ** 2 for i in range(0, int(math.sqrt(n)) + 1)]
              dp = [float('inf')] * (n + 1)
              # bottom case
              dp[0] = 0
              for i in range(1, n + 1):
                  for square in square_nums:
                      if i < square:
                          break
                      dp[i] = min(dp[i], dp[i - square] + 1)
              return dp[-1]

          順便補充一下:「四平方定理」:任何一個正整數(shù)都可以表示成不超過四個整數(shù)的平方之和。推論:滿足四數(shù)平方和定理的數(shù)n(四個整數(shù)的情況),必定滿足

          這個自己是不知道的,大家想深入:https://leetcode-cn.com/problems/perfect-squares/solution/wan-quan-ping-fang-shu-by-leetcode/

          下面是四平方定理的代碼

          def numSquares(self, n):
                  """
                  :type n: int
                  :rtype: int
                  """

                  while n % 4 == 0
                      n /= 4 
                  if n % 8 == 7
                      return 4 
                  a = 0 
                  while a**2 <= n: 
                      b = int((n - a**2)**0.5
                      if a**2 + b**2 == n: 
                          return (not not a) + (not not b) 
                      a += 1 
                  return 3

          Leetcode 300 最長上升子序列

          給定一個無序的整數(shù)數(shù)組,找到其中最長上升子序列的長度。

          示例:

          輸入: [10,9,2,5,3,7,101,18] 輸出: 4 解釋: 最長的上升子序列是 [2,3,7,101],它的長度是 4。說明:

          可能會有多種最長上升子序列的組合,你只需要輸出對應的長度即可。你算法的時間復雜度應該為 O(n2) 。

          對于Runsen這個菜鳥來說,關鍵還是怎么找出dp和轉(zhuǎn)移方程,dp[i]是第i個最長上升子序列。那么

          $$dp[i] = max(dp[i], dp[k] + 1)       其中 0<k<i-1 $$="" class Solution:
              def lengthOfLIS(self, nums: List[int]) -> int:
                  # 如果定義dp dp[i] 最長上升子序列 那么 dp[i] = max(dp[i], dp[k] + 1)  0<k<i-1
                  m = len(nums)
                  if m <= 1:
                      return  m
                  dp = [ 1 for _ in range(m)]
                  for i in range(1,m):
                      for j in range(i):
                          if nums[i] > nums[j]:
                              dp[i] = max(dp[i], dp[j]+ 1 ) 
                  return max(dp)

          Leetcode 322  零錢兌換

          給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函數(shù)來計算可以湊成總金額所需的最少的硬幣個數(shù)。如果沒有任何一種硬幣組合能組成總金額,返回 -1。

          示例 1:

          輸入: coins = [1, 2, 5], amount = 11 輸出: 3 解釋: 11 = 5 + 5 + 1 示例 2:

          輸入: coins = [2], amount = 3 輸出: -1

          「零錢兌換實際上就是完全背包的題目,也可以看作下樓梯的問題的變種」

          class Solution:
              def coinChange(self, coins: List[int], amount: int) -> int:
                  # 第一步:定義dp數(shù)組或變量,首先明確題目說每種硬幣的數(shù)量是無限的,但是會給定一個固定的 amount 金額,我們需要用最少的硬幣數(shù)湊出這個金額,如果是01背包問題就是[0]開始;
                  # 因此這個是一個完全背包的題目,還是下樓梯的問題的變種。完全背包求最小,那么初始就要時最大
                  dp = [float('inf')] * (amount + 1)
                  # 計算的起點 0 塊錢當然是 0
                  dp[0] = 0
                  # 狀態(tài)轉(zhuǎn)移方程:f(11) = min(f(10),f(9),f(6)) + 1  
                  for i in range(amount + 1):
                      for j in coins:
                          if i-j >=0 :
                              dp[i] = min(dp[i],dp[i-j] + 1 )
                  if dp[amount] > amount:
                      # 如果dp[amount]  是amount + 1 ,說明了沒有匹配的方式
                      return -1
                  return dp[-1]

          「至此完全背包就到這里結(jié)束了,完全背包注意dp的定義,求最大還是最小,完全背包的關鍵詞就次數(shù)是無限的」


          更多的文章

          點擊下面小程序



          - END -


          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  北条麻妃久久精品 | 国产肉体ⅩXXX137大胆图片 | 欧美精品18videosex性欧美 | 女人18片毛片90分钟免费播放 | 日韩中文字幕精品视频 |