1. 程式人生 > >動態規劃問題筆記1-揹包問題

動態規劃問題筆記1-揹包問題

最近刷題時碰到了動態規劃的問題,最開始覺得很難,無從下手,研究了一下動態規劃問題,覺得很神奇,做點兒筆記記錄下。
結合具體的問題來理解比單獨研究理論更形象一些。

問題:

要從物品重量為[2,3,5,5,10,2,8]的7個物體中選擇幾個物體放入容量為15的揹包,恰好放滿,總共有幾種方案?

動態規劃理論:

採用動態規劃的方法來做這樣的問題比較合適,動態規劃採用空間換時間的策略,對於把大的問題換成小的問題,而小的問題中又相互關聯的一類問題效果很好。本題中就有這樣 的特徵。
此處理論分析來自這裡:https://www.cnblogs.com/variance/p/6909560.html
這裡寫圖片描述
圖片中abc三個公式詳細解析:
a)式表示前

i個物品中挑選放入承重為0的揹包中和沒有物品放入承重為j的揹包中是相等為0。
b)式表明:如果第i個物品的重量大於揹包的容量,則裝人前i個物品得到的最大價值和裝入前i1個物品得到的最大價值是相同的,即物品i不能裝入揹包。
c)式表明:如果第i個物品的重量小於揹包的容量,則會有一下兩種情況:
(1)如果把第i個物品裝入揹包,則揹包物品的價值等於第i1個物品裝入容量位jWi 的揹包中的價值加上第i個物品的價值Vi;
(2)如果第i個物品沒有裝入揹包,則揹包中物品價值就等於把前i1個物品裝入容量為j的揹包中所取得的價值。
顯然,取二者中價值最大的作為把前
i
個物品裝入容量為j的揹包中的最優解。

具體做法

生成一個7行15+1列的二維陣列由於儲存大動態規劃的結果;其中的列代表揹包重量依次為0-15,每一行代表一個物品的重量。
對於每個物體,如果物體的重量大於揹包的最大容積,則該物體不能裝入揹包,只能使用前面的物體來裝填揹包;
如果物體的重量小於揹包的最大容積,比較該物體放入揹包和為放入揹包的最大價值值,取最大的;

#include<iostream>
#include<vector>

using namespace std;
#define SUM_MAX 1000
int dp[SUM_MAX][SUM_MAX];

template
<typename T> T max(const T& a, const T& b) { if (a > b)return a; else return b; } int dpCal(int n, int sum, vector<int>& A) { for (int i = 0; i <n; i++) { dp[i][0] = 1;//將物品i裝入容量為0的揹包的方法只有一種,即不放入物品,所以設定為1 } for (int j = 1; j <= sum; j++) { dp[0][j] = 0;//將第一行的1-sum列設定為0 } dp[0][A[0]] = 1;//將重量為A[0]的第一個物品放入容量為A[0]的揹包只有一種方法,所以設定為1 for (int i = 1; i <n; i++)//對第一個物品已經處理完畢,只需要從從第二個物品開始迴圈 { for (int j = 0; j <= sum; j++)//對每個容量為j的揹包進行處理 { if (A[i]>j) dp[i][j] = dp[i - 1][j];//當物品i的重量大於揹包的容量時,裝不下該物品,裝入之前的物品 else //當物品i的重量小於揹包的容量時,比較裝入該物品時與不裝入該物品時的價值大小(本題的每個物體價值可以認為是1),取最大的值。 dp[i][j] = max<int>(dp[i - 1][j],dp[i - 1][j] + dp[i - 1][j - A[i]]); } } return dp[n-1][sum]; } int main() { int n, sum; cin >> n >> sum; if (sum > SUM_MAX)exit(1); vector<int> A(n, 0); for (int i = 0; i < n; i++) { cin >> A[i]; } int method = 0; method = dpCal(n, sum, A); printf("動態規劃表:\n"); for (int i = 0; i <n; i++) { for (int j = 0; j <= sum; j++) { printf("%-4d", dp[i][j]); } printf("\n"); } printf("\n可用的方法數:%3d\n",method); system("pause"); return 0; }

輸入:
7 15
5 5 10 2 3 4 6
輸出:
這裡寫圖片描述