動態規劃問題筆記1-揹包問題
最近刷題時碰到了動態規劃的問題,最開始覺得很難,無從下手,研究了一下動態規劃問題,覺得很神奇,做點兒筆記記錄下。
結合具體的問題來理解比單獨研究理論更形象一些。
問題:
要從物品重量為[2,3,5,5,10,2,8]的7個物體中選擇幾個物體放入容量為15的揹包,恰好放滿,總共有幾種方案?
動態規劃理論:
採用動態規劃的方法來做這樣的問題比較合適,動態規劃採用空間換時間的策略,對於把大的問題換成小的問題,而小的問題中又相互關聯的一類問題效果很好。本題中就有這樣 的特徵。
此處理論分析來自這裡:https://www.cnblogs.com/variance/p/6909560.html
圖片中abc三個公式詳細解析:
a)式表示前
b)式表明:如果第個物品的重量大於揹包的容量,則裝人前個物品得到的最大價值和裝入前個物品得到的最大價值是相同的,即物品不能裝入揹包。
c)式表明:如果第個物品的重量小於揹包的容量,則會有一下兩種情況:
(1)如果把第個物品裝入揹包,則揹包物品的價值等於第個物品裝入容量位 的揹包中的價值加上第個物品的價值;
(2)如果第個物品沒有裝入揹包,則揹包中物品價值就等於把前個物品裝入容量為的揹包中所取得的價值。
顯然,取二者中價值最大的作為把前
具體做法
生成一個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
輸出: