動態規劃之完全背包

引言:

完全背包?隸屬于動態規劃中的背包問題。而 01背包 又是完全背包的基石,所以不懂01背包的,有必要了解一下。

什么是完全背包?

01背包問題:有一個背包承重為V,有N個物品,每個物品的價值(value)為v,重量為(weight)為w

每個物品只能取1次,求問背包,最多能裝下多大價值的物品。

完全背包問題:有一個背包承重為V,有N個物品,每個物品的價值(value)為v,重量為(weight)為w,每個物品無限次存取,求問背包,最多能裝下多大價值的物品。

如上01背包與完全背包的區別就在于,能無限次存取。

舉例

如題:一個能稱重為4的背包,共有3件可裝物品。對應價值重量如下圖所示,求最多能裝下多大價值的物品。

1、分析下標的含義:

dp[i][j] 表示,物品[ 0~i ] 每個物品,每個物品能取無數次,放入到容量為?j?的背包內,價值總和最大為多少?

2、遞推公式:

拿dp[1][4]舉例字,物品1,價值value(20),重量weight(3)。

如上圖所示,有兩種情況:

  • 不選擇物品本身:直接繼承物品0,也就dp[0][4] = 60;
  • 選擇該物品:dp[ 1 ][ 4-weight ]+value =?dp[ 1 ][ 1 ]+20 也就是35;

然后從兩種選擇中,選取。

最后得出遞推公式:dp[i][j] = max(dp[i-1][j] , dp[i][j-weight] + value);

3、推導代碼(二維):

下標的含義 與 遞推公式都得出來了,代碼不就直接出來了嗎:

#include <iostream>
#include <vector>
using namespace std;// 用于存儲最終的最大價值,不過在當前代碼中未實際使用該變量
int maxValue = 0;// 物品的重量和價值數組
// weight 數組存儲每個物品的重量,例如 weight[0] 是第一個物品的重量
vector<int> weight = {1, 3, 4, 5, 6};
// value 數組存儲每個物品的價值,例如 value[0] 是第一個物品的價值
vector<int> value = {1, 3, 4, 5, 6};int main(){// 背包的最大容量int bagweight = 6;// 定義二維動態規劃數組 dp// dp[i][j] 表示前 i 個物品放入容量為 j 的背包中所能獲得的最大價值int dp[weight.size()][bagweight + 1];// 初始化 dp 數組的第一行,即只考慮第一個物品的情況for(int i = 0; i <= bagweight; ++i){// 如果當前背包容量 i 小于第一個物品的重量if(i < weight[0]) {// 則無法放入第一個物品,最大價值為 0dp[0][i] = 0;} else {// 若能放入第一個物品,最大價值為第一個物品的價值// 這里由于是第一個物品,所以可以簡單理解為重復放入第一個物品來填滿背包dp[0][i] = dp[0][i - weight[0]] + value[0];}}// 外層循環遍歷物品,從第二個物品開始(索引為 1)// weight 數組的大小代表物品的個數for(int i = 1; i < weight.size(); ++i){// 內層循環遍歷背包的容量,從 0 到最大容量 bagweightfor(int j = 0; j <= bagweight; ++j){// 如果當前背包容量 j 小于第 i 個物品的重量if(j < weight[i]) {// 則無法放入第 i 個物品,最大價值和前 i - 1 個物品放入容量為 j 的背包的最大價值相同dp[i][j] = dp[i - 1][j];} else {// 若能放入第 i 個物品,需要在兩種情況中取最大值// 情況 1:不放入第 i 個物品,最大價值為 dp[i - 1][j]// 情況 2:放入第 i 個物品,此時最大價值為 dp[i - 1][j - weight[i]] + value[i]dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);}}}// 返回 0 表示程序正常結束return 0;
}
4、壓縮(一維滾動數組)

得出二維數組之后,經觀察得到,每一行代碼,都是由本行,或者上一行推導出來的:

dp[i][j] = max(dp[i-1][j] , dp[i][j-weight] + value);

故:我們可以用疊加的思維,將二維數組 壓縮 成一維數組,因不斷地疊加,滾動之名也由此而來。

    int v[3]={15,20,30};int w[3] = {1,3,4};int dp[5];for(int i=0; i<3; ++i){for(int j=w[i]; j<5; ++j){dp[j] = max(dp[j],dp[j-w[i]]+v[i]);}}

理論到此結束


大綱:(經典算法題)

?1、零錢兌換 II--01背包,過渡,首次接觸動規數據越界問題

?2、組合總和 Ⅳ--排列問題-完全背包,深度思考遍歷背包與容量的順序問題

?3、爬樓梯--排列問題-動態規劃

?4、零錢兌換--組合問題,巧妙求最小值

?5、單詞拆分--結合哈希表


1、零錢兌換 II

給你一個整數數組?coins?表示不同面額的硬幣,另給一個整數?amount?表示總金額。

請你計算并返回可以湊成總金額的硬幣組合數。如果任何硬幣組合都無法湊出總金額,返回?0?。

假設每一種面額的硬幣有無限個。?

題目數據保證結果符合 32 位帶符號整數。

    示例 1:

    輸入:amount = 5, coins = [1, 2, 5]
    輸出:4
    解釋:有四種方式可以湊成總金額:
    5=5
    5=2+2+1
    5=2+1+1+1
    5=1+1+1+1+1
    

    示例 2:

    輸入:amount = 3, coins = [2]
    輸出:0
    解釋:只用面額 2 的硬幣不能湊成總金額 3 。
    

    示例 3:

    輸入:amount = 10, coins = [10] 
    輸出:1
    

    提示:

    • 1 <= coins.length <= 300
    • 1 <= coins[i] <= 5000
    • coins?中的所有值?互不相同
    • 0 <= amount <= 5000
    class Solution {
    // 本題相當于是(等和子集、粉碎石頭、目標和、一和零的降智難度)
    // 這道題目,跟神經病一樣,數組非開到最大
    public:int change(int amount, vector<int>& coins) {vector<unsigned long long> dp(amount+1,0);dp[0]=1;for(int i=0; i<coins.size(); ++i){for(int j=coins[i]; j<=amount; ++j){dp[j] = dp[j]+dp[j-coins[i]];}}return dp[amount];}
    };
    2、組合總和 Ⅳ

    給你一個由?不同?整數組成的數組?nums?,和一個目標整數?target?。請你從?nums?中找出并返回總和為?target?的元素組合的個數。

    題目數據保證答案符合 32 位整數范圍。

    示例 1:

    輸入:nums = [1,2,3], target = 4
    輸出:7
    解釋:
    所有可能的組合為:
    (1, 1, 1, 1)
    (1, 1, 2)
    (1, 2, 1)
    (1, 3)
    (2, 1, 1)
    (2, 2)
    (3, 1)
    請注意,順序不同的序列被視作不同的組合。
    

    示例 2:

    輸入:nums = [9], target = 3
    輸出:0
    

    提示:

    • 1 <= nums.length <= 200
    • 1 <= nums[i] <= 1000
    • nums?中的所有元素?互不相同
    • 1 <= target <= 1000
    class Solution {// 理解dp的,遍歷順序,比推導公式難多了!!挑戰思維// 總是有超出界限的數目,因為指數級增加,(2的多少次方)
    public:int combinationSum4(vector<int>& nums, int target) {vector<int> dp(target+1);dp[0] = 1;for(int i=0; i<=target; ++i){for(int j=0; j<nums.size(); ++j){ // 疊加,指數爆炸性增長,2的多少次方,所以需要限制dp[i]+dp[i-nums[j]]<INT32_MAXif(i>=nums[j] && dp[i]<INT32_MAX - dp[i-nums[j]]) dp[i] = dp[i] + dp[i-nums[j]];}}return dp[target];}
    };
    3、爬樓梯

    題目描述

    假設你正在爬樓梯。需要 n 階你才能到達樓頂。?

    每次你可以爬至多m (1 <= m < n)個臺階。你有多少種不同的方法可以爬到樓頂呢??

    注意:給定 n 是一個正整數。

    輸入描述

    輸入共一行,包含兩個正整數,分別表示n, m

    輸出描述

    輸出一個整數,表示爬到樓頂的方法數。

    輸入示例

    3 2

    輸出示例

    3

    提示信息

    數據范圍:
    1 <= m < n <= 32;

    當 m = 2,n = 3 時,n = 3 這表示一共有三個臺階,m = 2 代表你每次可以爬一個臺階或者兩個臺階。

    此時你有三種方法可以爬到樓頂。

    1. 1 階 + 1 階 + 1 階段
    2. 1 階 + 2 階
    3. 2 階 + 1 階
    #include <iostream>
    #include <vector>
    using namespace std;
    int main(){int n,m;cin>>n>>m;vector<int> dp(n+1,0);dp[0] = 1;for(int i = 0; i<=n; ++i){for(int j=1; j<=m; ++j){if(i>=j) dp[i] = dp[i-j]+dp[i];}}cout<<dp[n];return 0;
    }
    
    4、零錢兌換

    給你一個整數數組?coins?,表示不同面額的硬幣;以及一個整數?amount?,表示總金額。

    計算并返回可以湊成總金額所需的?最少的硬幣個數?。如果沒有任何一種硬幣組合能組成總金額,返回?-1?。

    你可以認為每種硬幣的數量是無限的。

    示例?1:

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

    示例 2:

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

    示例 3:

    輸入:coins = [1], amount = 0
    輸出:0
    

    提示:

    • 1 <= coins.length <= 12
    • 1 <= coins[i] <= 231 - 1
    • 0 <= amount <= 104
    class Solution {
    public:int coinChange(vector<int>& coins, int amount) {vector<long long> dp(amount+1,INT32_MAX);dp[0] = 0;for(int i=0; i<coins.size(); ++i){for(int j=coins[i]; j<=amount; ++j){dp[j] = min(dp[j], dp[j-coins[i]]+1); }}return dp[amount]==INT32_MAX?-1:dp[amount];}
    };
    5、單詞拆分

    給你一個字符串?s?和一個字符串列表?wordDict?作為字典。如果可以利用字典中出現的一個或多個單詞拼接出?s?則返回?true

    注意:不要求字典中出現的單詞全部都使用,并且字典中的單詞可以重復使用。

    示例 1:

    輸入: s = "leetcode", wordDict = ["leet", "code"]
    輸出: true
    解釋: 返回 true 因為 "leetcode" 可以由 "leet" 和 "code" 拼接成。
    

    示例 2:

    輸入: s = "applepenapple", wordDict = ["apple", "pen"]
    輸出: true
    解釋: 返回 true 因為 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。注意,你可以重復使用字典中的單詞。
    

    示例 3:

    輸入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
    輸出: false
    

    提示:

    • 1 <= s.length <= 300
    • 1 <= wordDict.length <= 1000
    • 1 <= wordDict[i].length <= 20
    • s?和?wordDict[i]?僅由小寫英文字母組成
    • wordDict?中的所有字符串?互不相同
    class Solution {// 相當于利用動態規劃,卡空檔位
    public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> uset(wordDict.begin(),wordDict.end()); // 存vector<bool> dp(s.size()+1,false);dp[0] = true;for(int i=1; i<=s.size(); ++i){for(int j=1; j<=i; ++j){string str = s.substr(i-j,j);if(uset.find(str)!=uset.end() && dp[i-j]) dp[i] = true;}}return dp[s.size()];}
    };

    知識點:
    1、遍歷順序:(組合數與排列數

    coins存放硬幣數組amount 是要組成的金額數目

    組合數
    for(int i=0; i<coins.size(); i++){ // 先遍歷物品for(int j=coins[i]; j<=amount; j++){ // 在遍歷背包dp[j] = dp[j] + dp[j-coins[i]];}    
    }

    核心邏輯:每次固定一個物品,然后更新所有能容納該背包容量的組合數。

    舉例分析(coins = [1,5],amount = 6):

    1. 處理物品 1
      • 從 j=1 開始,所有 j>=1 的背包容量都會加上 dp [j-1]。
      • 此時 dp 數組記錄的是僅使用物品 1 的組合數(全 1 的序列)。
    2. 處理物品 5
      • 從 j=5 開始,所有 j>=5 的背包容量會加上 dp [j-5]。
      • 此時計算的是在已使用物品 1 的基礎上,添加物品 5 的組合。
      • 最終得到的組合是類似 {1,1,1,1,1,1}、{1,1,1,1,5} 等,不會出現 5 在前 1 在后的情況,因為物品是按順序處理的,每個物品只能在其之后的容量中被添加。
    排列數
    for(int j=0; j<=amount; ++j){for(int i=0; i<coins.size(); ++i){if(j>=coins[i]) dp[j] += dp[j-coins[i]];}    
    }

    核心邏輯:每次固定一個數,嘗試將所有物品都放入,從而更新組合數。

    舉例分析(coins = [1,5],amount = 6):

    1. 當 j=1 時
      • 遍歷物品 1,dp [1] += dp [0](即 1 種方式:{1})。
    2. 當 j=5 時
      • 遍歷物品 1,dp [5] += dp [4](此時 dp [4] 可能已包含多個 1 的組合)。
      • 遍歷物品 5,dp [5] += dp [0](即 1 種方式:{5})。
    3. 當 j=6 時
      • 遍歷物品 1,dp [6] += dp [5](包含 {1,5} 和 {5,1} 嗎?)
      • 遍歷物品 5,dp [6] += dp [1](即 {5,1})。
    2、多重背包:

    多重背包,其實與01背包非常的相似。

    有N種物品和一個容量為V 的背包。第i種物品最多有Mi件可用,每件耗費的空間是Ci ,價值是Wi 。求解將哪些物品裝入背包可使這些物品的耗費的空間 總和不超過背包容量,且價值總和最大。

    所以,往往只需要將重復的物品攤開即可。


    借鑒博客:

    1、算法之動態規劃(DP)求解完全背包問題

    2、動態規劃---完全背包問題詳解

    3、完全背包理論基礎-二維DP數組


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

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

    相關文章

    Codeforces Round 1003 (Div. 4)

    ABCDE略 F 如果這個序列有兩個一樣的數挨著或者中間只隔一個其他的數&#xff0c;那么這個數就是多數。可以用反證法&#xff0c;構造一個多值序列無法不包含以上兩種結構。只需要在樹上找這兩種結構就可以了 #include <bits/stdc.h> #define int long long using nam…

    金融數據分析(MATLAB)個人學習筆記(5):金融實證分析實例

    一、國內外常用金融數據庫簡介 &#xff08;一&#xff09;國外數據庫 1. CRSP數據庫 CRSP&#xff08;Center for Research in Security Prices,證券價格研究中心&#xff09;是美國芝加哥大學商研所金融研究中心的產品。收集的美國股票和指數數據來源主要為紐約證券交易所…

    硬件基礎(3):三極管(4):關于三極管的壓降

    文章目錄 三極管的壓降使用與測量注意事項 三極管的壓降 三極管的“壓降”通常是指在一定工作狀態下&#xff0c;三極管不同電極之間產生的電壓差。對于常見的雙極性晶體管&#xff08;BJT&#xff09;而言&#xff0c;最常討論的壓降通常包括以下幾個部分&#xff1a; 基-發射…

    [深度學習]圖像分類項目-食物分類

    圖像分類項目-食物分類(監督學習和半監督學習) 文章目錄 圖像分類項目-食物分類(監督學習和半監督學習)項目介紹數據處理設定隨機種子讀取文件內容圖像增廣定義Dataset類 模型定義遷移學習 定義超參Adam和AdamW 訓練過程半監督學習定義Dataset類模型定義定義超參訓練過程 項目介…

    5.go切片和map

    切片的概念 數組和切片相比較切片的長度是不固定的&#xff0c;可以追加元素&#xff0c;在追加時可能會使切片的容量增大&#xff0c;所以可以將切片理解成 "動態數組"&#xff0c;但是&#xff0c;它不是數組&#xff0c;而是構建在數組基礎上的更高級的數據結構。…

    在 Windows 上安裝 PowerShell 的多種方法與完整指南

    原文&#xff1a;在 Windows 上安裝 PowerShell 的多種方法與完整指南 | w3cschool筆記 在 Windows 上安裝 PowerShell 有多種方式。每種安裝方法都適用于不同的場景和工作流。請選擇最適合您需求的方法。 WinGet&#xff1a;推薦在 Windows 客戶端上安裝 PowerShell 的方式MS…

    云原生算力引擎:分布式推理的流體動力學

    引言&#xff1a;算力黑洞的引力擾動 OpenAI推理集群日處理4.5億次請求&#xff0c;CUDA 12.3實現μs級張量切換。特斯拉Dojo超算芯片間延遲0.5ns&#xff0c;阿里巴巴PAI平臺節省58%訓練時長。HuggingFace模型庫下載量突破3億次&#xff0c;AWS Inferentia芯片能效比提升8倍。…

    MySQL MVCC的快照讀和當前讀區別,Redis的RDB+AOF混合持久化流程。

    MySQL MVCC 的快照讀和當前讀區別 快照讀 (Snapshot Read) 定義: 讀取數據的歷史版本&#xff08;快照&#xff09;&#xff0c;基于 MVCC&#xff08;多版本并發控制&#xff09;實現。特點: 不加鎖&#xff0c;非阻塞讀。返回事務開始時的快照數據&#xff0c;確保一致性。…

    Cesium 自定義路徑導航材質

    cesium 自定義路徑導航紋理圖片隨便更換&#xff0c;UI 提供設計圖片即可達到效果&#xff1b; 打開小馬的weix 關注下 搜索“技術鏈” 回復關鍵詞《《路徑》》獲取原始代碼&#xff1b; 拿到就能用輕松解決&#xff01;幫忙點個關注吧&#xff01;

    3月25號

    添加圖片的一些例子: // 創建一個二維數組,用來管理數據int[][] data new int[4][4]; // 記錄空白方塊的位置int x0;int y0; // 定義一個變量,記錄當前展示圖片的路徑String path"E:\\java\\jigsawgame\\路飛\\路飛"; // 加載圖片細節: // …

    【機器學習】什么是支持向量機?

    什么是支持向量機&#xff1f; 支持向量機&#xff08;SVM&#xff0c;Support Vector Machine&#xff09;是一種強大的機器學習算法&#xff0c;常用于分類問題&#xff0c;也可以用于回歸問題。它的核心思想是通過找到一個最佳的“超平面”來將不同類別的數據分開&#xff…

    10分鐘打造專屬AI助手!ToDesk云電腦/順網云/海馬云操作DeepSeek哪家強?

    文章目錄 一、引言云計算平臺概覽ToDesk云電腦&#xff1a;隨時隨地用上高性能電腦 二 .云電腦初體驗DeekSeek介紹版本參數與特點任務類型表現 1、ToDesk云電腦2、順網云電腦3、海馬云電腦 三、DeekSeek本地化實操和AIGC應用1. ToDesk云電腦2. 海馬云電腦3、順網云電腦 四、結語…

    Spring Boot 一個接口實現任意表的 Excel 導入導出

    Java的web開發需要excel的導入導出工具&#xff0c;所以需要一定的工具類實現&#xff0c;如果是使用easypoi、Hutool導入導出excel&#xff0c;會非常的損耗內存&#xff0c;因此可以嘗試使用easyexcel解決大數據量的數據的導入導出&#xff0c;且可以通過Java8的函數式編程解…

    QT原子變量:QAtomicInteger、QAtomicPointer、QAtomicFlag

    引言&#xff1a;原子變量為何重要&#xff1f; 在多線程編程中&#xff0c;共享數據的原子性訪問是保證線程安全的核心。傳統互斥鎖雖然有效&#xff0c;但會帶來性能損耗和死鎖風險。QT提供的原子類型&#xff08;QAtomicInteger、QAtomicPointer、QAtomicFlag&#xff09;通…

    大模型金融企業場景落地應用

    一、商業銀行體系 1. 江蘇銀行 企業背景&#xff1a;江蘇銀行是總部位于江蘇南京的全國性股份制商業銀行&#xff0c;在城商行中資產規模位居前列&#xff0c;積極擁抱金融科技&#xff0c;將數字化轉型作為核心戰略之一。近年來&#xff0c;江蘇銀行持續加大在人工智能、大數…

    卡特蘭數在數據結構上面的運用

    原理 Catalan數是一個數列&#xff0c;其第n項表示n個不同結點可以構成的二叉排序樹的數量。Catalan數的第n項公式為&#xff1a; &#xfffc; 其中&#xff0c;&#xfffc;是組合數&#xff0c;表示從2n個元素中選擇n個元素的組合數。 Catalan數的原理可以通過以下方式理解&…

    影視后期工具學習之PR(中)

    pr剪輯之旅----聲音設計 第五課 鏡頭語言和綠幕摳像 超級鍵效果(超級鍵通過簡單的吸管取色和參數調整,即可實現專業級摳像與合成效果。無論是綠幕替換背景,還是創意雙重曝光,都能輕松駕馭。建議結合「Alpha 通道」視圖觀察透明區域,逐步優化細節,最終導出高質量視頻。)…

    使用BootStrap 3的原創的模態框組件,沒法彈出!估計是原創的bug

    最近在給客戶開發一個CRM系統&#xff0c;其中用到了BOOTSTRAP的模態框。版本是3。由于是剛開始用該框架。所以在正式部署到項目中前&#xff0c;需要測試一下&#xff0c;找到框架中的如下部分。需要說明的是。我用的asp.net mvc框架開發。測試也是在asp.net mvc環境下。 復制…

    Camera2 與 CameraX 閑談

    目錄 &#x1f4c2; 前言 1. &#x1f531; Camera2 2. &#x1f531; CameraX 3. &#x1f531; Camera2 與 CameraX 1&#xff09;使用復雜度與開發效率 2&#xff09;控制能力與應用場景 3&#xff09;設備兼容性與穩定性 4&#xff09;更新與維護 4. &#x1f4a0…

    【大語言模型_8】vllm啟動的模型通過fastapi封裝增加api-key驗證

    背景&#xff1a; vllm推理框架啟動模型不具備api-key驗證。需借助fastapi可以實現該功能 代碼實現&#xff1a; rom fastapi import FastAPI, Header, HTTPException, Request,Response import httpx import logging# 創建 FastAPI 應用 app FastAPI() logging.basicConfig(…