完全背包
完全背包:
题目描述:
有N中物品和一个容量是V的背包,每种物品都有无限多件可用。
有i种物品的体积是v[i] ,价值是 w[i].
求解将哪些物品装在背包,可使这些物品的总体积不超过背包容量,且总价值最大。
DP分析:
首先是朴素版本(二维完全背包) 时间复杂度:最坏是O(n^3)
#include<iostream> #include<algorithm> using namespace std; const int N = 1010; int f[N][N]; int n,m; int v[N],w[N]; int main() { 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 = 0;j <= m;j ++) for(int k = 0;k * v[i] <= j;k ++) f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]); cout << f[n][m] << endl; return 0; }
提示:
这里分析的不包含第i个物品时为f[i - 1][ j ],但因为i从小到大遍历,则f[ i ][ j ]首先取自于后者,
则之后的赋值f[ i ][ j ]时用的都是当前i下的f[i - 1][ j ],也就是自己理解的滚动数组的原理
其余代码较为简单就不解释了,下面给出优化后的代码
完全背包问题(优化一:推导优化)时间复杂度O(n^2)
代码如下:
#include<iostream> #include<algorithm> using namespace std; const int N = 1010; int f[N][N]; int n,m; int v[N],w[N]; int main() { 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 = 0;j <= m;j ++) { f[i][j] = f[i - 1][j]; if(j >= v[i]) f[i][j] = max(f[i][j] , f[i][j - v[i]] + w[i]); } cout << f[n][m] << endl; return 0; }
注释:
本次优化将k完全优化掉,将原来的f[ i ][ j ] 求值完全优化为 f[ i ][ j ] = max( f[i - 1][ j ] ,f[ i ][ j -v[ i ] ] + w[ i ]);
完全背包(优化二:一维数组优化)时间复杂度O(n^2)
#include<iostream> #include<algorithm> using namespace std; const int N = 1010; int f[N]; int n,m; int v[N],w[N]; int main() { 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 = v[i];j <= m;j ++) f[j] = max(f[j] ,f[j - v[i]] + w[i]); cout << f[m] << endl; return 0; }
注释:本次优化仍然使用了滚动数组原理。
ps:第一次写完全背包笔记,希望各位聚聚批评指正QAQ