地址 https://www.acwing.com/problem/content/description/2/ios
題目描述
有 N 件物品和一個容量是 V 的揹包。每件物品只能使用一次。算法
第 i 件物品的體積是 vi,價值是 wi。數組
求解將哪些物品裝入揹包,可以使這些物品的整體積不超過揹包容量,且總價值最大。
輸出最大價值。網絡
輸入格式
第一行兩個整數,N,V,用空格隔開,分別表示物品數量和揹包容積。ide
接下來有 N 行,每行兩個整數 vi,wi,用空格隔開,分別表示第 i 件物品的體積和價值。優化
輸出格式
輸出一個整數,表示最大價值。spa
數據範圍
0<N,V≤1000
0<vi,wi≤1000code
樣例 輸入樣例 4 5 1 2 2 4 3 4 4 5 輸出樣例: 8
算法1
(初步動態規劃)
最開始的動態規劃想法 就是二維數組
dp[i][j]記錄 在選擇i個物品下 j揹包容積下的最大價值
狀態轉移方程式視頻
C++ 代碼blog
1 #include <iostream> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int N= 1010; 7 8 int n,m; 9 10 int dp[N][N]; 11 int v[N]; 12 int w[N]; 13 14 int main() 15 { 16 cin >> n >> m; 17 18 for(int i = 1;i <= n;i++){ 19 cin >> v[i] >> w[i]; 20 } 21 22 for(int i = 1;i<=n;i++){ 23 for(int j = 1;j<=m;j++){ 24 dp[i][j] = dp[i-1][j]; 25 if(j >= v[i]) 26 dp[i][j] = max(dp[i-1][j] , dp[i-1][j-v[i]]+w[i]); 27 } 28 } 29 30 cout << dp[n][m]; 31 32 33 return 0; 34 }
根據acwing up主的視頻和網絡上的《揹包九講》 空間存儲上還可在優化
算法2
(進階動態規劃)
咱們能夠將二維DP降爲一維DP
這個能夠看作在i的循環狀況下 咱們每次計算j(容量)的可裝的最大價值
那麼初次進入i+1 的循環時候,咱們須要利用i輪次的結果來計算i+1的結果
dp[i+1][j]在0 1 狀況下只有兩種可能 在上一輪的結果下 選擇放入當前物品 或者不放入當前物品
1 不放入當前物品的話
那麼 dp[i+1][j] = dp[i][j]; //利用上一輪的結果
2 放入當前物品的話
那麼 dp[i+1][j] = dp[i][j-v[i]]+w[i]; //利用上一輪的結果
因爲咱們始終只須要最新的i+1層的結果 那麼實際上能夠使用一維數組dp[j]來記錄每層的結果,
當從i層進入i+1層後,dp[i+1][j]的結果 實際能夠使用dp[i][j]存儲,其實就是 dp[j] = dp[j];j++(或者j–);
因爲計算機語言的特性,在執行dp[j] = dp[j]的時候 咱們必須保證等號右邊的dp[j]是沒被改動過的,這就要保證j是降序
由於dp[j]= max(dp[j],dp[j-v[i]]); dp[j]的賦值對低於j的[j-v[i]]有依賴,必須降序排列,才能保證賦值的時候等號右邊的dp[j]是沒被改動過的
C++ 代碼
1 #include <iostream> 2 #include <algorithm> 3 4 using namespace std; 5 6 const int N= 1010; 7 8 int n,m; 9 10 int dp[N]; 11 int v[N]; 12 int w[N]; 13 14 int main() 15 { 16 cin >> n >> m; 17 18 for(int i = 1;i <= n;i++){ 19 cin >> v[i] >> w[i]; 20 } 21 22 for(int i = 1;i<=n;i++){ 23 for(int j = m;j>= v[i];j--){ 24 dp[j] = max(dp[j] , dp[j-v[i]]+w[i]); 25 } 26 } 27 28 cout << dp[m]; 29 30 return 0; 31 }
做者:defddr連接:https://www.acwing.com/solution/acwing/content/2170/來源:AcWing著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。