题目:https://www.acwing.com/problem/content/3/
完全背包相较于01背包区别在于每种物品的个数是无限的。
按照如上的分析,写出的代码
1 #include<iostream> 2 using namespace std; 3 const int N=1010; 4 int n,m; 5 int v[N],w[N]; 6 int f[N][N]; 7 int main(void){ 8 cin>>n>>m; 9 for(int i=1;i<=n;i++) cin>>v[i]>>w[i]; 10 for(int i=1;i<=n;i++){ 11 for(int j=0;j<=m;j++){ 12 for(int k=0;k*v[i]<=j;k++){ 13 f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]); 14 } 15 } 16 } 17 cout<<f[n][m]; 18 return 0; 19 }
然后我们会发现,这样写最坏复杂度是O(N^3),显然不够快。
发现可以利用之前列已经算出来的结果。
f ( i , j ) = MAX ( f (i-1 , j) , f(i-1 , j-vi)+wi ,f(i-1 , j-2*vi)+2*wi , ......... , f ( i , j-k*vi)+k*wi )
f ( i,j-vi)= MAX ( f (i-1 , j-vi) , f(i-1 , j-2*vi)+wi , ......... , f ( i , j-k*vi)+(k-1)*wi )
可以发现,计算 f (i , j) 时可以直接利用f(i , j-vi)的结果。
1 for(int i=1;i<=n;i++){ 2 for(int j=0;j<=m;j++){ 3 if(j>=v[i]){ 4 f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]); 5 }else{ 6 f[i][j]=f[i-1][j]; 7 } 8 } 9 }
可以发现,这和01背包太像了,因为计算 f [ i ] [ j ] 只用到了上一层的结果。
所以同样的,这可以用滚动数组优化,或者直接优化成一维。
1 //滚动数组 2 for(int i=1;i<=n;i++){ 3 for(int j=0;j<=m;j++){ 4 if(j>=v[i]){ 5 f[i%2][j]=max(f[(i-1+2)%2][j],f[i%2][j-v[i]]+w[i]); 6 }else{ 7 f[i%2][j]=f[(i-1+2)%2][j]; 8 } 9 } 10 } 11 //一维优化 12 for(int i=1;i<=n;i++){ 13 for(int j=v[i];j<=m;j++){ 14 f[j]=max(f[j],f[j-v[i]]+w[i]); 15 } 16 }