背包九讲之二:完全背包问题:一个物品允许选多次
Posted 谢哥在彼方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包九讲之二:完全背包问题:一个物品允许选多次相关的知识,希望对你有一定的参考价值。
有 N 件物品和一个容量是 V 的背包。每种物品都有无限件可用。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例
10
代码如下:
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 /* 5 f[i][j]表示只看前i个物品,总体积是j的情况下,总价值最大是多少 6 result = f[n]f[v] 7 1.不选第i个物品,f[i][j]=f[i-1][j]; 8 2.选第i个物品,f[i][j]=f[i-1][j-k*v[i]]+k*w[i](v[i]是体积,w[i]是价值,k是物品最大个数) 9 f[0][0]=0; 10 */ 11 const int array_size = 1001; 12 int f[array_size][array_size], v[array_size], w[array_size], N, V; 13 int main() { 14 cin >> N >> V; 15 for (int i = 1; i <= N; ++i) { 16 cin >> v[i] >> w[i]; 17 for (int j = 0; j <= V; ++j) { 18 f[i][j] = f[i - 1][j]; 19 for (int k = 1; k <= j / v[i]; ++k) 20 if (j >= k*v[i]) 21 f[i][j] = max(f[i][j], f[i - 1][j - k*v[i]] + k*w[i]); 22 } 23 24 } 25 cout << f[N][V]; 26 }
优化后如下:
#include<iostream> #include<algorithm> using namespace std; const int array_size = 1001; int f[array_size], v[array_size], w[array_size], N, V; int main() { cin >> N >> V; for (int i = 1; i <= N; ++i) { cin >> v[i] >> w[i]; /* 相当于01背包问题换了j的遍历顺序,结果就是第i轮(前i个物品) 中,先算f[j-v[i]],再算f[j] 数学归纳法证明优化后算法成立: 1、前1个物品中:f[1]=2,f[2]=4,f[3]=6,f[4]=8,f[5]=10,显然f[j]都是正确的。 2、假设在前i-1个物品中,f[j]都是正确的。 3、前i个物品中,对于某个j而言,如果最优解包含k个v[i],则一定会枚举到f[j-k*v[i]] f[j-k*v[i]]是如何得到的呢?f[j-k*v[i]]=max{f[j-k*v[i]],f[j-k*v[i]-v[i]]+w[i]} (由于j正序,f[j-k*v[i]]为前i-1个物品的值,f[j-k*v[i]-v[i]]为前i个物品的值) 最后会传递到max{f[v[i]],f[0]+w[i]}处。因为f[v[i]]一定正确(2中已假设前i-1个物品 中的f[j]全都正确),f[0]一定正确(=0),w[i]一定正确,所以max{f[v[i]],f[0]+w[i]} 一定正确=>f[j-k*v[i]]一定正确=>f[j]一定正确。 综上,证明成立。 */ for (int j = v[i]; j <= V; ++j) f[j] = max(f[j], f[j -v[i]] + w[i]); } cout << f[V]; } /* 若是要求物品恰好装满背包时的最大价值,只需 初始化时将f[0]置0,f[1]-f[V]都置-INF就可以了。 确保所有状态都是由f[0]转移过来。 */
以上是关于背包九讲之二:完全背包问题:一个物品允许选多次的主要内容,如果未能解决你的问题,请参考以下文章