一、01背包
题目
- 有n件物品,容量为V的背包
- 放入第 i 件物品耗费的费用是ci,得到的价值是wi
- 求解将哪些物品装入背包可使价值总和最大
特点
每种物品仅有1件,可以选择放或不放。
状态转移方程
dp[j]表示背包内放入物品费用为 j 时的最大价值
dp[j] = max { dp[j], dp[ j - ci ] + wi }
初始化
- 要求恰好装满背包:dp[0]=0,dp[1..V] = -INF
- 不要求装满背包:dp[0..V] = 0
伪代码
for(int i=1;i<=n;i++)
{
for(int j=V;j>=ci;j--)
{
dp[j]=max(dp[j],dp[j-ci]+wi);
}
}
cout<<dp[V]<<endl;
二、完全背包
题目
- 有n件物品,容量为V的背包,每种物品都有无限件可用
- 放入第 i 件物品耗费的费用是ci,得到的价值是wi
- 求解将哪些物品装入背包可使这些物品耗费的费用总和不超过V,且价值总和最大。
特点
每种物品有无限件
状态转移方程
dp[j]表示背包内放入物品费用为 j 时的最大价值
dp[j] = max { dp[j], dp[ j - ci ] + wi }
初始化
- 要求恰好装满背包:dp[0]=0,dp[1..V] = -INF
- 不要求装满背包:dp[0..V] = 0
伪代码
for(int i=1;i<=n;i++)
{
for(int j=ci;j<=V;j++)
{
dp[j]=max(dp[j],dp[j-ci]+wi);
}
}
cout<<dp[V]<<endl;
三、多重背包
题目
- 有n件物品,容量为V的背包,第 i 种物品最多有mi件可用
- 放入第 i 件物品耗费的费用是ci,得到的价值是wi
- 求解将哪些物品装入背包可使这些物品耗费的费用总和不超过V,且价值总和最大。
特点
每种物品件数固定
状态转移方程
dp[j]表示背包内放入物品费用为 j 时的最大价值
dp[j] = max { dp[j], dp[ j - ci ] + wi }
转化为01背包问题求解
将件数mi用二进制分解成若干个件数的集合
(例:15=1111,可分解成 0001,0010,0100,1000 四个数字)
即:一个正整数n可被分解成 1+2+4+…+2k-1+n-2k+1的形式
k是满足n-2k+1 > 0的最大整数
初始化
- 要求恰好装满背包:dp[0]=0,dp[1..V] = -INF
- 不要求装满背包:dp[0..V] = 0
伪代码
for(int i=0;i<n;i++)
{
for(int j=1;j<=m[i];j<<1)
{
value[count]=j*w[i];//价值
cost[count++]=j*c[i];//体积
m[i]-=j;
}
if(m[i]>0)
{
value[count]=m[i]*w[i];
cost[count++]=m[i]*c[i];
}
memset(dp,0,sizeof(dp));
for(int i=0;i<count;i++)
{
for(int j=V;j>=cost[i];j--)
{
dp[j]=max(dp[j],dp[j-cost[i]]+value[i]);
}
}
cout<<dp[V]<<endl;