【動態規劃】背包問題 {01背包問題;完全背包問題;二維費用背包問題}

一、背包問題概述

背包問題(Knapsackproblem)是?種組合優化的NP完全問題。

問題可以描述為:給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內,我們如何選擇,才能使得物品的總價格最?。

根據物品的個數,分為如下幾類:

  • 01背包問題:每個物品只有?個
  • 完全背包問題:每個物品有?限多個
  • 多重背包問題:每件物品最多有si個
  • 混合背包問題:每個物品會有上?三種情況…
  • 分組背包問題:物品有n組,每組物品里有若干個,每組里最多選一個物品

其中上述分類里面,根據背包是否裝滿,?分為兩類:

  • 不?定裝滿背包
  • 背包?定裝滿

優化?案:

  • 空間優化-滾動數組
  • 單調隊列優化
  • 貪?優化

根據限定條件的個數,又分為兩類:

  • 限定條件只有?個:比如體積->普通的背包問題
  • 限定條件有兩個:比如體積+重量->?維費?背包問題

根據不同的問法,又分為很多類:

  • 輸出?案
  • 求?案總數
  • 最優?案
  • ?案可?性

其實還有很多分類,但是我們僅需了解即可。
因此,背包問題種類非常繁多,題型非常豐富,難度也是非常難以捉摸。但是,盡管種類非常多,都是從01背包問題演化過來的。所以,?定要把01背包問題學好。


二、相關編程題

2.1 01背包問題

2.1.1 01背包(模板)

題目鏈接

【模板】01背包_牛客題霸_牛客網 (nowcoder.com)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

編寫代碼

#include <iostream>
#include <cstring>
using namespace std;
#define N 1010int n, V;
int v[N], w[N];
int dp[N][N];int main() {//讀入數據cin >> n >> V;for(int i = 1; i <= n; ++i) //注意所有下標從1開始{cin >> v[i] >> w[i];}//解決第一問for(int i = 1; i <= n; ++i){for(int j = 1; j <= V; ++j){dp[i][j] = dp[i-1][j]; // 不選i物品if(j>=v[i]) //要保證不越界,有空間存放v[i]dp[i][j] = max(dp[i][j], w[i]+dp[i-1][j-v[i]]); //選i物品}}cout << dp[n][V] << endl;//解決第二問memset(dp, 0, sizeof(dp));for(int j = 1; j <= V; ++j) dp[0][j] = -1; //-1表示恰好裝滿體積j無解for(int i = 1; i <= n; ++i){for(int j = 1; j <= V; ++j){dp[i][j] = dp[i-1][j]; // 不選i物品if(j>=v[i] && dp[i-1][j-v[i]]!=-1) //條件1保證不越界,有空間存放v[i];條件2保證恰好裝滿dp[i][j] = max(dp[i][j], w[i]+dp[i-1][j-v[i]]); //選i物品}}cout << (dp[n][V]==-1? 0:dp[n][V]) << endl;
}//空間優化
int dp[N];int main() {//讀入數據...//解決第一問for(int i = 1; i <= n; ++i){for(int j = V; j>=v[i]; --j) //注意從右往左遍歷dp[j] = max(dp[j], w[i]+dp[j-v[i]]);}cout << dp[V] << endl;//解決第二問memset(dp, 0, sizeof(dp));for(int j = 1; j <= V; ++j) dp[j] = -1; //-1表示恰好裝滿體積j無解for(int i = 1; i <= n; ++i){for(int j = V; j>=v[i]; --j){if(dp[j-v[i]]!=-1)dp[j] = max(dp[j], w[i]+dp[j-v[i]]);}}cout << (dp[V]==-1? 0:dp[V]) << endl;
}

2.1.2 分割等和子集

題目鏈接

416. 分割等和子集 - 力扣(LeetCode)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

  • 01背包必須裝滿
  • 為什么不用-1標識無解?因為其狀態表示中自帶無解判斷(false)

編寫代碼

//空間優化
class Solution {
public:bool canPartition(vector<int>& nums) {int n = nums.size();int sum = 0;for(auto e : nums) sum+=e;if(sum%2==1) return false;vector<bool> dp(sum/2+1);dp[0] = true;for(int i = 1; i <= n; ++i){for(int j = sum/2; j >= nums[i-1]; --j)dp[j] = dp[j] || dp[j-nums[i-1]];}return dp[sum/2];}
};

2.1.3 目標和

題目鏈接

494. 目標和 - 力扣(LeetCode)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

  • 01背包必須裝滿
  • 為什么不用-1標識無解?因為其狀態表示中自帶無解判斷(0種選法)

編寫代碼

//空間優化
class Solution {
public:int findTargetSumWays(vector<int>& nums, int target) {int n = nums.size();int sum = 0;for(auto e : nums) sum+=e;int a = (sum+target)/2;if(a<0 || (sum+target)%2==1) return false; //a是所有正數的和;必須是偶數能被2整除;vector<int> dp(a+1);dp[0] = 1;for(int i = 1; i <= n; ++i){for(int j = a; j >= nums[i-1]; --j)dp[j] += dp[j-nums[i-1]];}return dp[a];}
};

2.1.4 最后一塊石頭的重量Ⅱ

題目鏈接

1049. 最后一塊石頭的重量 II - 力扣(LeetCode)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

  • 01背包不必裝滿

編寫代碼

//空間優化
class Solution {
public:int lastStoneWeightII(vector<int>& stones) {int n = stones.size();int sum = 0;for(auto e : stones) sum+=e;int aim = sum/2;vector<int> dp(aim+1);for(int i = 1; i <= n; ++i){for(int j = aim; j >=stones[i-1]; --j)dp[j] = max(dp[j], stones[i-1]+dp[j-stones[i-1]]);}return sum-dp[aim]*2;}
};

2.2 完全背包問題

2.2.1 完全背包(模板)

題目鏈接

【模板】完全背包_牛客題霸_牛客網 (nowcoder.com)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

和01背包唯一的不同點就是每個物品可以選擇無數次,因此在選擇i物品的狀態轉移方程中有所變化。

提示:綜合了01背包、通配符匹配、正則表達式匹配的考點

編寫代碼

#include <iostream>
#include <cstring>
using namespace std;const int N = 1010;
int n, V;
int v[N], w[N];
int dp[N][N];int main() {//讀入數據cin >> n >> V;for(int i = 1; i <= n; ++i)cin >> v[i] >> w[i];//解決第一問for(int i = 1; i <= n; ++i){for(int j = 1; j <= V; ++j){dp[i][j] = dp[i-1][j];if(j >= v[i])dp[i][j] = max(dp[i][j], dp[i][j-v[i]]+w[i]);}}cout << dp[n][V] << endl;//解決第二問memset(dp, 0, sizeof(dp));for(int j = 1; j <= V; ++j) dp[0][j] = -1;for(int i = 1; i <= n; ++i){for(int j = 1; j <= V; ++j){dp[i][j] = dp[i-1][j];if(j >= v[i] && dp[i][j-v[i]]!=-1)dp[i][j] = max(dp[i][j], dp[i][j-v[i]]+w[i]);}}cout << (dp[n][V]==-1? 0:dp[n][V]) << endl;
}//空間優化
int dp[N];int main() {//讀入數據...//解決第一問for(int i = 1; i <= n; ++i){for(int j = v[i]; j <= V; ++j) //注意從左往右遍歷{dp[j] = max(dp[j], dp[j-v[i]]+w[i]);}}cout << dp[V] << endl;//解決第二問memset(dp, 0, sizeof(dp));for(int j = 1; j <= V; ++j) dp[j] = -1;for(int i = 1; i <= n; ++i){for(int j = v[i]; j <= V; ++j){if(dp[j-v[i]]!=-1)dp[j] = max(dp[j], dp[j-v[i]]+w[i]);}}cout << (dp[V]==-1? 0:dp[V]) << endl;
}

2.2.2 零錢兌換

題目鏈接

322. 零錢兌換 - 力扣(LeetCode)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

提示:不能再像完全背包那樣用-1表示無解。因為這里求的是最小值,如果使用-1,而不選i位置無解,即使選擇i位置的零錢有解,也會在取min時取到-1。實際上我們設置無解為-1的初衷就是為了不參與后續的比較,因此可以用INF(無窮大)表示無解,這樣的話,在取min時永遠不會取到INF。

編寫代碼

class Solution {
public:int coinChange(vector<int>& coins, int amount) {const int INF = 0x3f3f3f3f;int n = coins.size();vector<vector<int>> dp(n+1, vector<int>(amount+1));for(int j = 1; j <= amount; ++j) dp[0][j] = INF;for(int i = 1; i <= n; ++i){for(int j = 1; j <= amount; ++j){dp[i][j] = dp[i-1][j];if(j >= coins[i-1])dp[i][j] = min(dp[i][j], dp[i][j-coins[i-1]]+1);}}return dp[n][amount]>=INF? -1:dp[n][amount];}
};//空間優化
class Solution {
public:int coinChange(vector<int>& coins, int amount) {const int INF = 0x3f3f3f3f;int n = coins.size();vector<int> dp(amount+1);for(int j = 1; j <= amount; ++j) dp[j] = INF;for(int i = 1; i <= n; ++i){for(int j = coins[i-1]; j <= amount; ++j)dp[j] = min(dp[j], dp[j-coins[i-1]]+1);}return dp[amount]>=INF? -1:dp[amount];}
};

2.2.3 零錢兌換Ⅱ

題目鏈接

518. 零錢兌換 II - 力扣(LeetCode)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

編寫代碼

class Solution {
public:int change(int amount, vector<int>& coins) {int n = coins.size();vector<int> dp(amount+1);dp[0] = 1;for(auto e : coins){for(int j = e; j <= amount; ++j)dp[j]+=dp[j-e];  }return dp[amount];}
};

2.2.4 完全平方數

題目鏈接

279. 完全平方數 - 力扣(LeetCode)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

編寫代碼

class Solution {
public:int numSquares(int n) {int m = sqrt(n);const int INF = 0x3f3f3f3f;vector<int> dp(n+1, INF);dp[0] = 0;for(int i = 1; i <= m; ++i){for(int j = i*i; j <= n; ++j)dp[j] = min(dp[j], dp[j-i*i]+1);}return dp[n];}
};

2.3 二維費用背包問題

2.3.1 一和零

題目鏈接

474. 一和零 - 力扣(LeetCode)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

  • 01背包,不必裝滿,二維費用

編寫代碼

//三維dp表
class Solution {
public:int findMaxForm(vector<string>& strs, int m, int n) {int cnt = strs.size();vector<vector<vector<int>>> dp(cnt+1, vector<vector<int>>(m+1, vector<int>(n+1)));for(int i = 1; i <= cnt; ++i){//統計以下字符串中0,1的個數int c0 = Count0(strs[i-1]);int c1 = strs[i-1].size()-c0;for(int j = 0; j <= m; ++j)for(int k = 0; k <= n; ++k){dp[i][j][k] = dp[i-1][j][k]; //不選i位置的字符串if(j>=c0 && k>=c1) //選i位置的字符串dp[i][j][k] = max(dp[i][j][k], dp[i-1][j-c0][k-c1]+1);}}return dp[cnt][m][n];}int Count0(const string& str){int cnt = 0;for(auto ch : str)if(ch == '0') ++cnt;return cnt;}
};//空間優化:二維dp表
class Solution {
public:int findMaxForm(vector<string>& strs, int m, int n) {int cnt = strs.size();vector<vector<int>> dp(m+1, vector<int>(n+1));for(int i = 1; i <= cnt; ++i){int c0 = Count0(strs[i-1]);int c1 = strs[i-1].size()-c0;for(int j = m; j >= c0; --j) //注意從大到小遍歷for(int k = n; k >= c1; --k){dp[j][k] = max(dp[j][k], dp[j-c0][k-c1]+1);}}return dp[m][n];}
};

2.3.2 盈利計劃

題目鏈接

879. 盈利計劃 - 力扣(LeetCode)

題目描述

在這里插入圖片描述

算法原理

在這里插入圖片描述

提示:k可以小于p[i],表示單單i項計劃的盈利就超過了最低限度k。但是作為數組的下標k-p[i]不能是負數,因此我們采取一個折中的方案,當k-p[i]<0時從前i-1項計劃中選擇的總利潤最低為0即可。

編寫代碼

//三維dp表
class Solution {
public:int profitableSchemes(int n, int m, vector<int>& group, vector<int>& profit) {int cnt = group.size();vector<vector<vector<int>>> dp(cnt+1, vector<vector<int>>(n+1, vector<int>(m+1)));for(int j = 0; j <= n; ++j) dp[0][j][0] = 1; //沒有計劃,沒有利潤,無論多少人數都可以選空for(int i = 1; i <= cnt; ++i){for(int j = 0; j <= n; ++j){for(int k = 0; k <= m; ++k){dp[i][j][k] = dp[i-1][j][k];if(j>=group[i-1])dp[i][j][k] += dp[i-1][j-group[i-1]][max(0, k-profit[i-1])];dp[i][j][k] %= (int)1e9+7;}}}return dp[cnt][n][m];}
};//空間優化:二維dp表
class Solution {
public:int profitableSchemes(int n, int m, vector<int>& group, vector<int>& profit) {int cnt = group.size();vector<vector<int>> dp(n+1, vector<int>(m+1));for(int j = 0; j <= n; ++j) dp[j][0] = 1;for(int i = 1; i <= cnt; ++i){for(int j = n; j >= group[i-1]; --j)for(int k = m; k >= 0; --k){dp[j][k] += dp[j-group[i-1]][max(0, k-profit[i-1])];dp[j][k] %= (int)1e9+7;}}return dp[n][m];}
};

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

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

相關文章

鏈接追蹤系列-07.logstash安裝json_lines插件

進入docker中的logstash 容器內&#xff1a; jelexbogon ~ % docker exec -it 7ee8960c99a31e607f346b2802419b8b819cc860863bc283cb7483bc03ba1420 /bin/sh $ pwd /usr/share/logstash $ ls bin CONTRIBUTORS Gemfile jdk logstash-core modules tools x-pack …

語音識別概述

語音識別概述 一.什么是語音&#xff1f; 語音是語言的聲學表現形式&#xff0c;是人類自然的交流工具。 圖片來源&#xff1a;https://www.shenlanxueyuan.com/course/381 二.語音識別的定義 語音識別&#xff08;Automatic Speech Recognition, ASR 或 Speech to Text, ST…

基于RAG大模型的變電站智慧運維-第十屆Nvidia Sky Hackathon參賽作品

第十屆Nvidia Sky Hackathon參賽作品 1. 項目說明 變電站是用于變電的設施&#xff0c;主要的作用是將電壓轉化&#xff0c;使電能在輸電線路中能夠長距離傳輸。在電力系統中&#xff0c;變電站起到了極為重要的作用&#xff0c;它可以完成電能的負荷分配、電壓的穩定、容錯保…

電影購票小程序論文(設計)開題報告

一、課題的背景和意義 隨著互聯網技術的不斷發展&#xff0c;人們對于購票的需求也越來越高。傳統的購票方式存在著排隊時間長、購票流程繁瑣等問題&#xff0c;而網上購票則能夠有效地解決這些問題。電影購票小程序是網上購票的一種新型應用&#xff0c;它能夠讓用戶隨時隨地…

06.截斷文本 選擇任何鏈接 :root 和 html 有什么區別

截斷文本 對超過一行的文本進行截斷,在末尾添加省略號(…)。 使用 overflow: hidden 防止文本超出其尺寸。使用 white-space: nowrap 防止文本超過一行高度。使用 text-overflow: ellipsis 使得如果文本超出其尺寸,將以省略號結尾。為元素指定固定的 width,以確定何時顯示省略號…

Selenium WebDriver中的顯式等待與隱式等待:深入理解與應用

在自動化測試中&#xff0c;尤其是在使用Selenium WebDriver進行Web應用的自動化測試時&#xff0c;等待元素加載完成是一個常見的需求。Selenium提供了兩種等待機制來處理這一問題&#xff1a;顯式等待&#xff08;Explicit Wait&#xff09;和隱式等待&#xff08;Implicit W…

筆記 4 :linux 0.11 中繼續分析 0 號進程創建一號進程的 fork () 函數

&#xff08;27&#xff09;本條目開始&#xff0c; 開始分析 copy_process () 函數&#xff0c;其又會調用別的函數&#xff0c;故先分析別的函數。 get_free_page &#xff08;&#xff09; &#xff1b; 先 介紹匯編指令 scasb &#xff1a; 以及 指令 sstosd &#xff1a;…

什么是架構設計師?定義、職責和任務,全方位解析需要具備的專業素質

目錄 1. 架構設計師的定義 2. 架構設計師的職責和任務 2.1 系統架構設計 2.1.1 模塊劃分 2.1.2 接口設計 2.1.3 通信方式 2.2 技術選型與決策 2.2.1 技術評估 2.2.2 技術選型 2.2.3 技術決策 2.3 性能優化與調優 2.3.1 性能分析 2.3.2 性能優化 2.3.3 性能調優 …

基于BitMap的工作日間隔計算

背景問題 在我們實際開發過程中&#xff0c;時常會遇到日期的間隔計算&#xff0c;即計算多少工作日之后的日期&#xff0c;在不考慮法定節假日的情況下也不是那么復雜&#xff0c;畢竟周六、周日是相對固定的&#xff0c;Java語言也提供了豐富的類來處理此問題。 然而&#x…

MVVM和MVC的原理以及它們的區別

MVVM&#xff08;Model-View-ViewModel&#xff09;和 MVC&#xff08;Model-View-Controller&#xff09;是兩種常見的前端架構模式&#xff0c;它們都旨在幫助組織和管理復雜的前端應用程序邏輯和視圖層。 MVC&#xff08;Model-View-Controller&#xff09; 原理&#xff1…

視圖庫對接系列(GA-T 1400)十七、視圖庫對接系列(本級)采集設備獲取

背景 這一章的話,我們寫寫如何獲取采集設備獲取,之前其實也有說過類似的 就我們訂閱的時候如果subscribeDetail=3的話,下級就會主動給我們推送采集設備。但這里的話,是下級主動推,如果下級平臺不支持,或者說可能因為某個原因推的不全,怎么辦? 我們能否主動獲取采集設備…

WPF學習(4) -- 數據模板

一、DataTemplate 在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;DataTemplate 用于定義數據的可視化呈現方式。它允許你自定義如何展示數據對象&#xff0c;從而實現更靈活和豐富的用戶界面。DataTemplate 通常用于控件&#xff08;如ListBox、…

知識圖譜和 LLM:利用 Neo4j 實現大型語言模型

這是關于 Neo4j 的 NaLLM 項目的一篇博客文章。這個項目是為了探索、開發和展示這些 LLM 與 Neo4j 結合的實際用途。 2023 年,ChatGPT 等大型語言模型 (LLM) 因其理解和生成類似人類的文本的能力而風靡全球。它們能夠適應不同的對話環境、回答各種主題的問題,甚至模擬創意寫…

NSSCTF中24網安培訓day1中web的題目

我flag呢 直接查看源代碼即可CtrlU [SWPUCTF 2021 新生賽]Do_you_know_http 用Burpsuite抓包&#xff0c;之后在User-agent下面添加XFF頭&#xff0c;即X-Forwarded-For:127.0.0.1 [SWPUCTF 2022 新生賽]funny_php 首先是php的弱比較&#xff0c;對于num參數&#xff0c;我們…

hot100 | 十一、二分搜索

1-leetcode35. 搜索插入位置 注意&#xff1a; 看Labuladong的書&#xff0c;知道while的判斷符號跟left right的關系 public int searchInsert(int[] nums, int target) {int left 0;int right nums.length - 1;while (left < right) {int mid left (right - left) /…

AI如何引領個人潛力的深度挖掘

AI如何引領個人潛力的深度挖掘 人工智能&#xff08;AI&#xff09;不僅是一場技術革命&#xff0c;更是對人類自身能力的一次深刻反思。本文旨在探討在AI時代下&#xff0c;個人如何挖掘并發揮自己的最大潛能&#xff0c;不僅在職場、教育領域找到新的定位&#xff0c;同時也…

PostgreSQL日志文件配置,記錄所有操作記錄

為了更詳細的記錄PostgreSQL 的運行日志&#xff0c;我們一般需要修改PostgreSQL 默認的配置文件&#xff0c;這里整理了一些常用的配置 修改配置文件 打開 PostgreSQL 配置文件 postgresql.conf。該文件通常位于 PostgreSQL 安裝目錄下的 data 文件夾中。 找到并修改以下配…

Python循環遍歷:深入理解與實戰應用

在Python編程中&#xff0c;循環遍歷是一種基本且強大的控制流結構&#xff0c;它允許我們重復執行一段代碼直到滿足某個條件為止。無論是處理數據集合&#xff08;如列表、元組、字典、集合等&#xff09;&#xff0c;還是執行重復的任務&#xff0c;循環遍歷都是不可或缺的工…

807.保持城市天際線

解題思路 首先找到四個主要方向&#xff08;東南西北&#xff09;的天際線情況。南北看是一樣的&#xff0c;東西看也是一樣的。所以統計出每行的最值&#xff0c;每列的最值&#xff0c;用一個n的數組存儲。分別存儲行和列的最值。最值的位置進行標記&#xff0c;然后對于其余…

【Qt 基礎】繪圖

畫筆 QPen pen; pen.setWidth(3); // 線條寬度 pen.setColor(Qt::red);// 畫筆顏色 pen.setStyle(Qt::DashLine);// 線條樣式 pen.setCapStyle(Qt::RoundCap);// 線端樣式 pen.setJoinStyle(Qt::BevelJoin);// 連接樣式 painter.setPen(pen);線條 線端 連接 畫刷 QBrush bru…