日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【动态规划】01背包问题+查找背包物品

發布時間:2024/1/1 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【动态规划】01背包问题+查找背包物品 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

一、0-1背包問題

二、問題分析

1、確定備忘錄的具體含義

2、狀態轉移方程

3、初始化

4、遍歷順序及輸出

5、回溯法求解最大價值時的背包物品?

三、總結?

四、完整代碼

一、0-1背包問題

給定種物品(每種物品均只有一個)和一背包。物品i的重量是,其價值為,背包的最大容量為。怎樣選擇裝入背包中的物品,使得其總價值最大?

例如:現有4種物品,其對應的重量和價值如圖所示,另有一最大容量為5的背包,求該背包所能裝下物品的最大價值?

物品?重量價值
024
113
246
335

二、問題分析

1、確定備忘錄的具體含義

dp[i][j]:任取第0~i件物品,放入容量為j的背包,能得到的最大價值 例:dp[1][2]=3的含義:任取物品0~物品1,放入容量為2的背包,能得到的最大價值(取物品1放入背包,其價值最大,為3)

dp[i][j] 的定義十分重要,狀態方程的書寫、數組初始化、遍歷順序和輸出結果都必須嚴格按照該定義進行書寫

2、狀態轉移方程

對于物品,它只有放與不放兩種狀態,當它能放入背包時,狀態轉移方程只需取兩種狀態的最大值; 否則,取不放入時的最大價值。

if (j < w[i]) dp[i][j] = dp[i - 1][j]; else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);

?3、初始化

從狀態轉移方程可知,欲求dp[i][j],需先確定dp[i-1][j]和dp[i-1][j-w[i]]的值(即需保證dp[i][j]的左上角數據已經處理完成),故我們需對第0行和第0列進行初始化.

//初始化第0列(即背包容量為0) for (i = 0; i < n; i++)dp[i][0] = 0; //初始化第0行(即只有物品0) for (j = 1; j <= max_weight; j++) {if (w[0] <= j) dp[0][j] = v[0];elsedp[0][j] = 0; }

4、遍歷順序及輸出

遍歷順序:求解dp[i][j]只需提前知道其左上角的數據,故以下兩種遍歷方式均可。

1、先遍歷背包再遍歷物品(即物品數固定,背包容量逐增至最大,物品再加1)

?2、先遍歷物品再遍歷背包(即背包容量固定,物品數逐增至最大,背包容量再加1)

輸出:dp[n-1][max_weight]: n件物品任取,放入容量為max_weight的背包,所得的最大價值。

//先遍歷物品再遍歷背包 for (i = 1; i < n; i++) { //遍歷物品for (j = 1; j <= max_weight; j++) { //遍歷背包if (j < w[i]) dp[i][j] = dp[i - 1][j];else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);} } //先遍歷背包再遍歷物品 for (j = 1; j <= max_weight; j++) { //遍歷背包for (i = 1; i < n; i++) { //遍歷物品if (j < w[i])dp[i][j] = dp[i - 1][j];elsedp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);} }

5、求解最大價值時的背包物品?

由狀態轉移方程(dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]))可知,當dp[i][j]dp[i-1][j]時,物品i被放入背包中(判斷條件),當dp[i][j]=0時,背包中已經沒有物品(結束條件)。

//回溯法求解裝入物品 i--; j--; //循環結束后,i=n,j=max_weight+1,故使用dp[n - 1][max_weight]須自減1 cout << "最大價值時的背包物品為:" << endl; while (dp[i][j]&&i>=0) { if (dp[i][j] != dp[i - 1][j]) {cout << "物品" << i << endl;j -= w[i]; //裝入物品i后背包的最大容量}i--; //物品i已經處理完成,接下來討論物品i-1 }

1、 使用dp[i][j](最大價值)前一定要對i,j進行處理,否則,運行時會拋出異常;

2、結束條件一定要加上i>=0,否則,運行結果可能會出現物品-1等錯誤。

3、該法得到的結果只為其中的一組最優解,可能還存在其他最優解,例如:當我們裝入物品0(2,4)和物品3(3,5)時,其最大價值也為9.

三、總結?

?1、0-1背包問題是背包問題的基礎。深入了解0-1背包問題(每件物品只有一個)是掌握完全背包問題(每件物品有無數個)、多重背包問題(不同物品數量不同)和分組背包(物品分為多組,每組最多選一個)的關鍵;

2、使用dp[i][j]數組時,一定要注意數組的界限問題,避免越界訪問造成錯誤。比如:剛開始的時候,我認為背包不存在容量為0的情況,故沒有將第一列初始化為0,導致輸出出錯,將dp[i][j]全部打印出來后,才知道是dp[1][1]出錯了,因為dp[1][1]=max(dp[0][1],dp[0][0]+v[0]),需要用到dp[0][0],造成越界。所以,檢驗算法的正確性,可以先人工求解出dp[i][j]數組,再用程序將其打印出來,這樣有利于我們快速找到問題所在。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 轉換表(打印)

轉換表(人工)
 012345
0004444
1034777
2034779
3034789

3、背包問題一定要先明確輔助數組的具體含義再確定轉換方程,根據轉換方程來確定初始化、遍歷順序和輸出結果。

四、完整代碼

#include<iostream> #include<algorithm> using namespace std;const int max_weight = 5; const int n = 4;int main() {int i, j;int w[n] = { 2,1,4,3 }; //重量int v[n] = { 4,3,6,5 }; //價值int dp[n][max_weight+1];//輔助數組//初始化第0列(即背包容量為0)for (i = 0; i < n; i++)dp[i][0] = 0;//初始化第0行(即只有物品0)for (j = 1; j <= max_weight; j++) {if (w[0] <= j) dp[0][j] = v[0];elsedp[0][j] = 0;}//狀態轉移//先遍歷物品再遍歷背包for (i = 1; i < n; i++) { //遍歷物品for (j = 1; j <= max_weight; j++) { //遍歷背包if (j < w[i]) dp[i][j] = dp[i - 1][j];else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);}}//輸出cout << dp[n - 1][max_weight] << endl;//回溯法求解裝入物品i--; j--; //循環結束后,i=n,j=max_weight+1,故使用dp[n - 1][max_weight]須自減1cout << "最大價值時的背包物品為:" << endl;while (dp[i][j]&&i>=0) { if (dp[i][j] != dp[i - 1][j]) {cout << "物品" << i << endl;j -= w[i]; //裝入物品i后背包的最大容量}i--; //物品i已經處理完成,接下來討論物品i-1}return 0; }

運行結果:?

總結

以上是生活随笔為你收集整理的【动态规划】01背包问题+查找背包物品的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。