完全背包问题:
给定一个有一定容量的背包,和n个物品,每个物品有无限件。
每个物品有其对应的体积和价值。
问背包最多能装下的物品的最大价值为多少。
输入格式:
第一行两个整数,N,V,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi 用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式:
输出一个整数,表示最大价值。
思路:
我们像01背包一样推导,面对第i件物品时,我们可以选0件、选1件、选2件……,那么方程就为:
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i] + w[i], f[i - 1][j - 2 * v[i] + 2 * w[i] ......)。
如果这样做的话,我们就需要加上一层循环来决定选几件物品。
我们发现:
f[i][j - v[i]] = max(f[i - 1][j - v[i]], f[i - 1][j - 2 * v[i]] + w[i], f[i - 1][j - 3 * v[i]] + 2 * w[i]......)
我们将f[i][j-v[i]]加上w[i]之后,就可以替换掉f[i][j]方程的除了第一项的所有项。
所以当v大于等于v[i]时,dp方程为:
f[i][j] = max(f[i - 1][j],f[i][j - v[i] + w[i])。
代码如下:
#include<iostream>using namespace std;const int N=1010;int n,V;int f[N][N];int main(){ cin>>n>>V; int v,w; for(int i=1;i<=n;i++){ cin>>v>>w; for(int j=0;j<=V;j++){ f[i][j]=f[i-1][j]; if(j>=v)f[i][j]=max(f[i][j],f[i][j-v]+w); } } cout<<f[n][V]; return 0;}
优化至一维:
和01背包不同,完全背包为状态是有本层的左边更新而来的,所以我们应该先把本层左边的状态先更新,所以是从前往后更新的。
代码如下:
#include<iostream>using namespace std;const int N = 1010;int n, V;int f[N];int main() { cin >> n >> V; int v, w; for (int i = 1; i <= n; i++) { cin >> v >> w; for (int j = v; j <= V; j++) { f[j] = max(f[j], f[j - v] + w);//小于v的默认为上一层的状态 } } cout << f[V]; return 0;}