完全背包
问题描述
有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。
第 i 种物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
DP_二维数组
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n,m;
int v[N],w[N],f[N][N]={0};
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-1][j],f[i][j-v[i]]+w[i]);
}
cout << f[n][m] << endl;
return 0;
}
核心公式推导
DP_一维数组
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n,m;
int v[N],w[N],f[N]={0};
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;
}
优化说明
上文推导出公式后
将零一背包 f[i] [j] = max(f[i] [j],f[i-1] [j-v[i]]+w[i])
与完全背包 f[i] [j] = max(f[i] [j],f[i] [j-v[i]]+w[i])
比较发现:只有 max函数 中的第二项代表的含义不同,完全背包中的这一项是已经被前面的循环修改了的值,而零一背包是未被修改的值,故前者内层循环采用递增顺序。
j - v[i]必定是小于j的,而递增保证了j - v[i] 在 j 之前就已经被修改了,所以采用递增
参考 ACWing算法基础课视频_完全背包