算法訓練營第三十天 | 動態規劃 (三)

提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔

文章目錄

  • 一、01背包問題理論基礎(一)
    • 動態規劃五部曲
      • 確定dp數組以及下標的含義
      • 確定遞推公式
      • 初始化dp數組
      • 確定遍歷順序
  • 二、01背包問題理論基礎(二)
    • 動態規劃五部曲
      • 確定dp數組以及下標的含義
      • 確定遞推公式
      • 初始化dp數組
      • 確定遍歷順序
      • 代碼
  • 三、Leetcode 416. 分割等和子集
    • 動態規劃五部曲
      • 確定dp數組以及下標的含義
      • 確定遞推公式
      • 初始化dp數組
      • 確定遍歷順序
    • 代碼


一、01背包問題理論基礎(一)

有n件物品和一個最多能背重量為 w 的背包。第 i 件物品的重量是 weight[i] ,得到的價值是 value[i] 。每件物品只能用一次,求解將哪些物品裝入背包里物品價值總和最大。

動態規劃五部曲

確定dp數組以及下標的含義

這里我們使用二維數組 dp[i][j]。其中 i 代表物品,j 代表背包。

dp 數組表示的含義是,當背包重量為 j 時,我們從 0i 個物品中進行取舍,能獲得的最大價值。

本題中 dp 數組的定義十分關鍵!

確定遞推公式

當我們背包重量為 i 的時候,我們一共有兩種情況。

  • 背包重量小于物品 i 的重量時,我們無法放入物品,所以我們直接繼承上一個狀態 dp[i-1][j] ,也就是當背包重量為 j 時,我們從 0i-1 個物品中進行取舍,能獲得的最大價值。
  • 當背包重量大于物品 i 的重量時,我們有兩種選擇,考慮是否選擇將物品 i 放入背包內。
  1. 不將物品 i 放入背包內,此時我們也是繼承上一個狀態 dp[i-1][j]
  2. 將物品 i 放入背包內,此時的狀態應為:當前背包容量減去物品 i 的重量在 0i-1 個物品中任意取的最大值再加上物品 i 的價值。,即 dp[i][j] = dp[i - 1][j - weight[i]] + value[i]

我們的目的是獲得最大的價值,所以當背包重量大于物品 i 的重量時,我們對兩種情況取最大值 max(dp[i - 1][j - weight[i]] + value[i], dp[i-1][j])

最后得出遞推公式:

if weight[i-1] > j:dp[i][j] = dp[i-1][j]
else:dp[i][j] = max[dp[i - 1][j - weight[i]] + value[i], dp[i-1][j]]

初始化dp數組

將二維數組理解成為一個表格,行代表物品,列代表背包重量。

我們當前要計算的表格是通過左上方的表格遞推出來的,所以我們要對第一列和第一行進行初始化。

第一行代表的是,當背包重量為 j 時,對第一個物品進行取舍,我們能得到的最大價值。
這時我們只有一個物品可以考慮,所以向右遍歷,當物品的重量大于等于背包重量時,表示這個物品可以放進背包內,這時右面的表格就初始化為第一個物品的價值。左面的表格就初始化為 0

第一列代表的是,當背包重量為 0 時,對前 i 個物品進行取舍能獲得的最大價值。背包重量是 0,當然什么物品也放不進去,所以第一列全部初始化為 0

其余位置都是通過遞推公式計算得出,所以初始值無所謂,全部初始化為 0

確定遍歷順序

很顯然,我們需要兩層 for 循環,那么到底是先遍歷物品還是先遍歷背包呢?

本題中先遍歷背包和先遍歷物品都可以!

  • 先遍歷物品的方式更符合動態規劃的自底向上的求解思路。先考慮只有一個物品時,對于不同背包容量的最大價值,然后逐步增加物品數量,計算在當前物品加入的情況下,不同背包容量的最大價值。這種方式可以清晰地看到狀態是如何逐步轉移和構建的
  • 先遍歷背包的方式則是先固定背包容量,然后看在這個容量下,不同物品組合能達到的最大價值。雖然代碼執行順序不同,但最終也能正確計算出所有狀態的最大價值。

代碼:

n, bagweight = map(int, input().split())weight = list(map(int, input().split()))
value = list(map(int, input().split()))dp = [[0] * (bagweight + 1) for _ in range(n)]for j in range(weight[0], bagweight + 1):dp[0][j] = value[0]for i in range(1, n):for j in range(bagweight + 1):if j < weight[i]:dp[i][j] = dp[i - 1][j]else:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])print(dp[n - 1][bagweight])

二、01背包問題理論基礎(二)

對于遞歸問題,有的時候我們當前狀態只是通過前面幾個狀態進行推導,如果定義一個很長的數組,那么大部分的空間是被浪費的,滾動數組就是在空間上進行優化的一種方法。

舉一個例子,斐波那契數列問題。我們的狀態轉移方程是 dp[i]=dp[i-1]+dp[i-2 。那么當前狀態是由前兩個狀態推導而來,當我們推導 dp[3] 的時候,dp[0] 就已經用不到了,所以我們完全可以將推導得到的 dp[3] 放在 dp[0] 的位置,這樣我們只開辟了三塊空間就能完成整個計算,大大節省了空間,這就是滾動數組的思想。

對于 01 背包問題,我們當前層的狀態都是由上一層的狀態推導而來,所以也可以使用滾動數組來進行優化。

動態規劃五部曲

確定dp數組以及下標的含義

dp[j] 表示背包重量為 weightp[j] 時,可以獲得的最大價值。

確定遞推公式

二維dp數組的遞推公式為: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
一維dp數組,其實就上一層 dp[i-1] 這一層 拷貝的 dp[i]來。
所以在 上面遞推公式的基礎上,去掉i這個維度就好。

遞推公式為:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

以下為分析:

dp[j] 為 容量為j的背包所背的最大價值。

dp[j] 可以通過 dp[j] - weight[i]] 推導出來,dp[j] - weight[i]] 表示容量為 j - weight[i] 的背包所背的最大價值。

dp[j - weight[i]] + value[i] 表示 容量為 [j - 物品i重量] 的背包 加上 物品 i 的價值。(也就是容量為 j 的背包,放入物品 i 了之后的價值即:dp[j]

此時 dp[j] 有兩個選擇,一個是取自己 dp[j] 相當于 二維dp數組中的 dp[i-1][j] ,即不放物品 i,一個是取 dp[j - weight[i]] + value[i] ,即放物品 i ,指定是取最大的,畢竟是求最大價值。

初始化dp數組

dp數組初始化的時候,都初始為 0 即可。

確定遍歷順序

我們在二維dp數組的時候,遍歷順序沒有要求,但是對于一維數組,這里有嚴格的順序。
我們的滾動數組的思想是當前層是由上一層拷貝而來,而每一層代表的是物品,所以我們要先便遍歷物品,再遍歷背包重量。

在遍歷背包重量的時候,一定要倒序遍歷。

因為在某一層,當前數值是由他左面推導而來,如果我們正序遍歷的話,新的值會覆蓋掉原來的值,這樣也就導致了某一個物品被多次使用。

代碼

n, bagweight = map(int, input().split())
weight = list(map(int, input().split()))
value = list(map(int, input().split()))dp = [0] * (bagweight + 1)  # 創建一個動態規劃數組dp,初始值為0dp[0] = 0  # 初始化dp[0] = 0,背包容量為0,價值最大為0for i in range(n):  # 應該先遍歷物品,如果遍歷背包容量放在上一層,那么每個dp[j]就只會放入一個物品for j in range(bagweight, weight[i]-1, -1):  # 倒序遍歷背包容量是為了保證物品i只被放入一次dp[j] = max(dp[j], dp[j - weight[i]] + value[i])print(dp[bagweight])

三、Leetcode 416. 分割等和子集

給你一個 只包含正整數的 非空 數組 nums 。請你判斷是否可以將這個數組分割成兩個子集,使得兩個子集的元素和相等。
示例:

輸入:nums = [1,5,11,5]
輸出:true
解釋:數組可以分割成 [1, 5, 5][11]

引用:

原文鏈接:https://programmercarl.com/0416.%E5%88%86%E5%89%B2%E7%AD%89%E5%92%8C%E5%AD%90%E9%9B%86.html
題目鏈接:https://leetcode.cn/problems/partition-equal-subset-sum/description/
視頻講解:https://www.bilibili.com/video/BV1rt4y1N7jE/

解決的問題是判斷集合里能否出現總和為 sum / 2 的子集,這相當于有一個只能裝重量為 sum / 2 的背包,商品就是集合里的數字,要判斷這些數字能否把背包裝滿。
對于這些數字商品而言,它們只有一個維度,即重量等于價值。當這些數字能裝滿承載重量為 sum / 2 的背包時,背包的價值也為 sum / 2
所以此問題可轉化為裝滿承載重量為 sum / 2 的背包時,其最大價值是多少,若最大價值是 sum / 2,就說明背包正好被商品裝滿,由于商品是數字且重量和價值相同,因此可以直接用 01 背包來解決這個問題。

動態規劃五部曲

確定dp數組以及下標的含義

dp[j] 表示背包重量為 weightp[j] 時,可以獲得的最大價值。

確定遞推公式

背包問題的遞推公式為:dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
那么這里重量和價值在同一個維度,所以我們的遞推公式改寫為
dp[j]=max(dp[j], dp[j-nums[i]]+nums[i])

初始化dp數組

dp數組初始化的時候,都初始為 0 即可。

確定遍歷順序

和我們01背包問題中的一維滾動數組遍歷方式一樣。

代碼

class Solution:def canPartition(self, nums: List[int]) -> bool:total_sum = sum(nums)if total_sum % 2 != 0:return Falsetarget = int(total_sum / 2)dp = [0] * (target+1)for i in range(len(nums)):for j in range(target, nums[i]-1, -1):dp[j] = max(dp[j], dp[j-nums[i]]+nums[i])return dp[target]==target

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/78199.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78199.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/78199.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

玩機搞機基本常識-------小米OLED屏幕機型怎么設置為永不休眠_手機不息屏_保持亮屏功能 拒絕“燒屏” ?

前面在幫一位粉絲解決小米OLED機型在設置----鎖屏下沒有永不休眠的問題。在這里&#xff0c;大家要明白為什么有些小米機型有這個設置有的沒有的原因。區分OLED 屏幕和 LCD屏幕的不同。從根本上拒絕燒屏問題。 OLED 屏幕的一些優缺點&#x1f49d;&#x1f49d;&#x1f49d; …

PostgreSQL使用LIKE右模糊沒有走索引分析驗證

建表&數據初始化可參考PostgreSQL 分區表——范圍分區SQL實踐 背景&#xff1a; 給t_common_work_order_log的handle_user_name新建索引后&#xff0c;使用LIKE右模糊匹配查詢時&#xff0c;發現走的全表掃描 CREATE INDEX order_log_handle_user_name_index ON t_commo…

【vue】【element-plus】 el-date-picker使用cell-class-name進行標記,type=year不生效解決方法

typedete&#xff0c;自定義cell-class-name打標記效果如下&#xff1a; 相關代碼&#xff1a; <el-date-pickerv-model"date":clearable"false":editable"false":cell-class-name"cellClassName"type"date"format&quo…

《Learning Langchain》閱讀筆記8-RAG(4)在vector store中存儲embbdings

什么是 vector store&#xff1f; 與專門用于存儲結構化數據&#xff08;如 JSON 文檔或符合關系型數據庫模式的數據&#xff09;的傳統數據庫不同&#xff0c;vector stores處理的是非結構化數據&#xff0c;包括文本和圖像。像傳統數據庫一樣&#xff0c;vector stores也能執…

用api的方式調用本地下載好的大模型(以llama為例,不是ollama!!!)

目錄 1、創建虛擬環境2、激活虛擬環境3、安裝相關庫4、編寫腳本&#xff08;test.py&#xff09;調用腳本5、bash中測試通信完美結果 1、創建虛擬環境 conda create -n myenv python3.12 -y2、激活虛擬環境 conda activate myenv3、安裝相關庫 pip install vllm fastapi uvi…

算力網絡(CFN)在跨校聯合科研中的應用:安全性挑戰與聯邦調度實踐

引言&#xff1a;科研協作的算力困境 上海交通大學與麻省理工學院聯合開展的高能物理模擬實驗&#xff0c;因算力資源分配不均導致部分節點連續72小時處于空轉狀態。這個典型案例揭示了當前跨機構科研協作的痛點&#xff1a;?算力資源無法實現安全可信的細粒度共享?。算力網…

高防IP+CDN組合:電商大促的“雙保險”防護方案

引言 電商大促期間&#xff0c;平臺流量呈爆發式增長&#xff0c;既要應對瞬時激增的訪問量&#xff0c;又要防范黑客趁機發起的DDoS攻擊、惡意爬蟲等威脅。單一防護手段往往難以兼顧性能與安全&#xff0c;而高防IPCDN組合通過“流量清洗加速分發”的雙重機制&#xff0c;為電…

# 構建詞匯表:自然語言處理中的關鍵步驟

構建詞匯表&#xff1a;自然語言處理中的關鍵步驟 在自然語言處理&#xff08;NLP&#xff09;任務中&#xff0c;詞匯表&#xff08;Vocabulary&#xff09;是文本數據預處理的核心組件之一。它將文本中的單詞或字符映射為數值索引&#xff0c;從而讓計算機能夠理解和處理語言…

SQL進階知識:七、數據庫設計

今天介紹下關于數據庫設計的詳細介紹&#xff0c;并結合MySQL數據庫提供實際例子。 數據庫設計是確保數據庫能夠高效、安全地存儲和管理數據的關鍵環節。良好的數據庫設計可以提高查詢性能、減少數據冗余、確保數據完整性&#xff0c;并簡化數據維護。以下是關于數據庫設計的詳…

python如何取消word中的縮進

在python-docx中&#xff0c;取消縮進可以通過將相應的縮進屬性設置為None或0來實現。以下是取消不同類型縮進的方法&#xff1a; 取消左縮進 from docx import Documentdoc Document(existing_document.docx)for paragraph in doc.paragraphs:# 取消左縮進paragraph.paragr…

Docker拉取鏡像代理配置實踐與經驗分享

Docker拉取鏡像代理配置實踐與經驗分享 一、背景概述 在企業內網環境中&#xff0c;我們部署了多臺用于測試與學習的服務器。近期&#xff0c;接到領導安排&#xff0c;需在其中一臺服務器上通過Docker安裝n8n應用程序。然而在實際操作過程中&#xff0c;遭遇Docker官方鏡像庫…

【數字圖像處理】立體視覺基礎(1)

成像 成像過程&#xff1a;三維空間坐標到二維圖像坐標的變換 相機矩陣&#xff1a;建立三維到二維的投影關系 相機的使用步驟&#xff08;模型-視圖變換&#xff09;&#xff1a; &#xff08;1&#xff09;視圖變換 &#xff08;2&#xff09;模型變換 &#xff08;3&…

實驗4:列表與字典應用

目的 &#xff1a;熟練操作組合數據類型。 試驗任務&#xff1a; 1. 基礎&#xff1a;生日悖論分析。如果一個房間有23人或以上&#xff0c;那么至少有兩個人的生日相同的概率大于50%。編寫程序&#xff0c;輸出在不同隨機樣本數量下&#xff0c;23 個人中至少兩個人生日相同的…

c++之網絡編程

網絡編程&#xff1a;使得計算機程序能夠在網絡中發送和接受數據&#xff0c;從而實現分布式系統和網絡服務的功能。 作用&#xff1a;使應用程序能夠通過網絡協議與其他計算機程序進行數據交換 基本概念 套接字&#xff08;socket&#xff09;&#xff1a; 套接字是網絡通信…

【Harmony_Bug】forEach + asyncawait 的異步陷阱

一、問題描述 今天在做一個RDB的小項目時&#xff0c;遇到一個問題&#xff0c;因為沒報錯其實也是不算是BUG&#xff0c;以下描述時我就直接說關鍵點&#xff0c;其他代碼忽略。 我的數據模型初始化有六條數據如圖 在持久化層&#xff0c;通過initUserData這個方法執行插入。…

大腸桿菌誘導蛋白時OD600=0.6-0.8添加IPTG的思考-實驗操作系列-009

一、為什么用OD600表示菌液濃度&#xff1f; 1. 光密度與吸光值的關系 OD600是指在600納米波長下的光密度&#xff08;Optical Density&#xff09;&#xff0c;也就是通過細菌懸浮液的光的吸收程度。根據比爾-朗伯定律&#xff0c;光密度與溶液中光學活性物質&#xff08;如…

OpenHarmony - 小型系統內核(LiteOS-A)(十),魔法鍵使用方法,用戶態異常信息說明

OpenHarmony - 小型系統內核&#xff08;LiteOS-A&#xff09;&#xff08;十&#xff09; 十四、魔法鍵使用方法 使用場景 在系統運行出現無響應等情況時&#xff0c;可以通過魔法鍵功能確定系統是否被鎖中斷&#xff08;魔法鍵也無響應&#xff09;或者查看系統任務運行狀態…

CUDA編程之Grid、Block、Thread線程模型

一、線程模型:Grid、Block、Thread概念 ?1. 層級定義? ?Thread(線程)? CUDA中最基本的執行單元,對應GPU的單個CUDA核心(SP)。每個線程獨立執行核函數指令,擁有獨立的寄存器和局部內存空間?。 ?Block(線程塊)? 由多個線程組成(通常為32的倍數),是邏輯上的并…

實戰交易策略 篇十九:君山居士熊市交易策略

文章目錄 系列文章熊市三大特征熊市操作思維強勢重勢,弱勢重質搶反彈重要前提和五大原則反彈逃頂操盤其他炒股的至高境界力戒“三進三出”八大心理誤區八大戒律股市不敗之法系列文章 實戰交易策略 篇一:奧利弗瓦萊士短線交易策略 實戰交易策略 篇二:杰西利弗莫爾股票大作手…

Flutter IOS 真機 Widget 錯誤。Widget 安裝后系統中沒有

錯誤信息&#xff1a; SendProcessControlEvent:toPid: encountered an error: Error Domaincom.apple.dt.deviceprocesscontrolservice Code8 "Failed to show Widget com.xxx.xxx.ServerStatus error: Error DomainFBSOpenApplicationServiceErrorDomain Code1 "T…