完全背包
完全背包就是一个物品可以无限次使用。
具体可以看01背包,完全背包就是状态计算的集合的划分不一样,状态表示和01背包是基本相似的,这里怎么划分呢,比如每件物品可以拿k次,如果0次的话就相当于不拿第i件,那就是f[i-1][j],大于0件的话就可以表示为f[i-1][j-k*v[i]]+k*w[i],就是先拿走第i件,i-1,再减去他的体积,有k个i,就是j-k*v[i],然后还得加回来,就+k*w[i],就得出了状态转移方程,其实拿0件我们也可以合并在一起,就相当于k=0,所以综上所述:
这是最基本的朴素做法。这个时间复杂度比较大。
#include<iostream> using namespace std; const int N = 1010; int n,m; int v[N],w[N]; int f[N][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; }
我们可以把它优化成二维的
#include<iostream> using namespace std; const int N = 1010; int n,m; int v[N],w[N]; int f[N][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; }
那其实这样看起来其实和01背包的代码差不多对吧,就有细微的不一样。
然后还能优化,可以将它优化到一维,
#include<iostream> using namespace std; const int N = 1010; int n,m; int v[N],w[N]; int f[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; }