有 N 種物品和一個容量是 VV 的背包。
第 i 種物品最多有 si 件,每件體積是 vi,價值是 wi。
求解將哪些物品裝入背包,可使物品體積總和不超過背包容量,且價值總和最大。
輸出最大價值。
輸入格式
第一行兩個整數N,V,用空格隔開,分別表示物品種數和背包容積。
接下來有 N行,每行三個整數vi,wi,si,用空格隔開,分別表示第 i 種物品的體積、價值和數量。
輸出格式
輸出一個整數,表示最大價值。
數據范圍
0<N≤1000
0<V≤2000
0<vi,wi,si≤2000
提示:
本題考查多重背包的二進制優化方法。
輸入樣例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
輸出樣例:
10
狀態計算
集合划分
第i個物品最多選多少個
f[i,j] = max(f[i-1,j-kv]+kw) k=0,1,2,…,s[i]
二進制優化
f[i,j] = Max(f[i-1,j], f[i-1,j-v]+w,f[i-1,j-2v]+2w,…,f[i-1,j-sv]+sw)
f[i,j-v]=Max(f[i-1,j-v], f[i-1,j-2v]+w,…, f[i-1,j-(s+1)v]+(s+1)w)
二進制的優化方式
s=1023
1,2,4,8,…,512
0~1023
把多種背包某個物品有s次,轉化為logS的物品的01背包問題,因此可以拼湊出問題的解
注意這里的湊數,最后一個是剩余的解
如 s=200
1,2,4,8,16,32,64,73
1~127
73~200
所以只湊出了0-200的解
s
1,2,4,8,..,2^k,c
c=s-(2^{k+1}-1)
c<2^{k+1}
s<=2^{k+2}-1;
優化步驟
總物品數:NlogS
時間:VNlogS
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 //N*log(s)*V 6 const int N = 11000;//N*log(s)向上取整 7 //總物品數:NlogS 8 9 int n,m; 10 int w[N];//重量 11 int v[N];//價值 12 int f[N];//[j], j重量的最大價值 13 14 int main() 15 { 16 cin >> n >> m; 17 18 int cnt = 0; 19 for(int i = 1;i <= n;i ++) 20 { 21 int a,b,s; 22 cin >> a >> b >> s; 23 int k = 1; 24 while(k <= s) 25 { 26 cnt++; 27 w[cnt] = a * k; 28 v[cnt] = b * k; 29 s -= k; 30 k *= 2; 31 } 32 33 if(s > 0) 34 { 35 cnt++; 36 w[cnt] = a * s; 37 v[cnt] = b * s; 38 } 39 } 40 n = cnt; 41 for(int i = 1;i <= n;i ++) 42 for(int j = m;j >= w[i];j --) 43 f[j] = max(f[j],f[j - w[i]] + v[i]); 44 45 46 cout << f[m] << endl; 47 48 return 0; 49 }