ABP框架 - 依賴注入
0 1揹包(每個物品選一次)
有N件物品和一個容量是 M的揹包。每件物品只能使用一次。
第i件物品的體積是vi,價值是wi。
求解將哪些物品裝入揹包,可使這些物品的總體積不超過揹包容量,且總價值最大。
輸出最大價值。
輸入格式
第一行兩個整數,N,VN,V,用空格隔開,分別表示物品數量和揹包容積。
接下來有N行,每行兩個整數vi,wi,用空格隔開,分別表示第i件物品的體積和價值。
輸出格式
輸出一個整數,表示最大價值。
資料範圍
0<N,M≤1000
0<vi,wi≤1000
輸入樣例
4 5
1 2
2 4
3 4
4 5
輸出樣例:
8
樸素做法:
思路:dp[i][j]表示前i個物品,體積為j的最優解。
對於第i個物品可選可不選。不選的dp[i][j]=dp[i-1][j];
選的話就是dp[i][j]=dp[i-1][j-v[i]]+w[i];為什麼呢,因為體積最大就只能是剛好,那麼前i-1個物品就要騰出空間給第i個物品,那前i個物品騰出的空間就是j-v[i];前提是j>=v[i],不然騰不出空間。
#include<bits/stdc++.h> using namespace std; const int MAXN = 1005; int v[MAXN]; // 重量 int w[MAXN]; // 價值 int f[MAXN][MAXN]; // f[i][j], j重量下前i個物品的最大價值int main() { int n, m; cin >> n >> m; for(int i = 1; i <= n; ++i) cin >> v[i] >> w[i]; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) { if(j <v[i]) f[i][j] = f[i-1][j];//太小了只能不選, else //選的話,在選和不選中取max f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i]); } cout<< f[n][m]; return 0; }
優化版:
思路:上面的程式碼中我們可以發現,f[i][j]的時候我們只用到了前面,我們只用到了f[i-1][j]或者f[i-1][j-v[i],所以我們可以按順序列舉i,即for(int i = 1; i <= n; i++),就可以保證我們每次都是用前面一層,所以可以將二維陣列濃縮成一維陣列;
在發現如果只剩下一維陣列了,當我們不選的時候,f[i][j] = f[i-1][j]就變成了f[j]=f[j],預設成立,這句就可以去掉了,所以我們可以直接從j>=w[i]列舉到m,但是我們發現f[j] = max(f[j], f[j-v[i]] + w[i])這句話是第i層更新的,為什麼呢,因為j從v[i]開始列舉,j-v[i]就<j,就會將f[j]從小到大在第i層更新了一遍,就將前面第i-1層的結果給覆蓋掉了,所以我們選擇逆序,從m開始列舉到v[i];即for(int j = m; j >= v[i]; j--)
#include<bits/stdc++.h> using namespace std; const int MAXN = 1005; int v[MAXN]; // 重量 int w[MAXN]; // 價值 int f[MAXN]; //int f[MAXN][MAXN]; // f[i][j], j重量下前i個物品的最大價值 int main() { int n, m; cin >> n >> m; for(int i = 1; i <= n; i++) cin >> v[i] >> w[i]; for(int i = 1; i <= n; i++) for(int j = m; j >= v[i]; j--) // for(int j = 1; j <= m; ++j) { // if(j < w[i]) //f[j]=f[j]; // f[i][j] = f[i-1][j];//太小了只能不選, // else //選的話,在選和不選中取max f[j] = max(f[j], f[j-v[i]]+w[i]); // f[i][j] = max(f[i-1][j], f[i-1][j-w[i]] + v[i]); } cout<<f[m]<<endl; //cout << f[n][m]; return 0; }