有 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 }