01背包
for(int i=1;i<=n;i++)
{
for(int j=0;j<=c;j++)
{
if(j<power[i])
dp[i][j]=dp[i-1][j];
else
dp[i][j]=max(dp[i-1][j],dp[i-1][j-power[i]]+val[i]);
}
}
dp[i][j]表示对于第i件物品,放入大小为j的背包中可以存在的最大价值
滚动数组写法
for(int i=2;i<=n;i++)
for(int j=c;j>=power[i];j--)
dp[j]=max(dp[j],dp[j-power[i]]+val[i]);
曾经写过的错误写法
for(int j=0;j<=c;j++)
{
if(j>=power[i])
{
dp[j]=max(dp[j],dp[j-power[i]]+val[i]);
ans=max(ans,dp[j]);
}
}
分析
滚动数组将上下层间的dp并为一层,直接在一层的基础上比较并进行修改。滚动写法需要倒着写,正着写会提前将上层数据篡改,影响后续结果
完全背包
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
for(int k=0;k*w[i]<=j;k++)
dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*val[i]);
}
}
滚动数组写法
for(int i=1;i<=n;i++)
{
for(int j=w[i];j<=m;j++)
{
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
没想到写01背包的错误写法阴差阳错奇迹般的写成了完全背包
多重背包
#include<bits/stdc++.h>
using namespace std;
int w[1005],val[1005],dp[1005],s[1005];
int main()
{
int n,v;
scanf("%d%d",&n,&v);
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&w[i],&val[i],&s[i]);
}
for(int i=0;i<n;i++)
{
for(int j=v;j>=0;j--)
{
for(int k=0;k<=s[i]&&k*w[i]<=j;k++)
dp[j]=max(dp[j],dp[j-k*w[i]]+k*val[i]);
}
}
printf("%d\n",dp[v]);
}
dp初始化的细节
正常情况下只需要将dp初始化为0即可。
但是有的题目可能会要求“恰好可以装满背包”的最优解。
对于这种题目,需要将dp初始化为-0x3f,再将dp[0]=0。
可以这样理解:对于dp[0],背包本身没有空间,即背包已经装满,且装入的价值为0,其合法最优解为0.而其他的空间,由于本身还没有最优解,赋值为负无穷