01背包
for(int i = 1; i <= n; ++i)
{
for(int j = V; j >= c[i]; --j)
{
dp[j] = max(dp[j],dp[j-c[i]]+a[i]);
}
}
完全背包
for(int i = 1; i <= n; ++i)
{
for(int j = c[i]; j <= V; j++)//与01背包不同,从前往后刷新即可以重复加物品,手动模拟下就能明白
{
dp[j] = max(dp[j],dp[j-c[i]]+a[i]);
}
}
注意:初始化方面的细节,如果要求恰好装满背包,那么在初始化时除了dp[0]为0其它dp[1..V]均设为-∞(求的是最大解,如果求的是最小解,则为∞) 如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。因为如果恰好背满的话,必须是由状态dp[0]转移而来,所以dp[0]要最靠近最优决策。
多重背包(二进制优化)
for(int i = 1; i <= n; ++i)
{
int k;
for(k = 1; k*2 <= count[i]; k *= 2)//count[i]为i物品的个数,本来是一个一个放,现在是成倍的放,比如9,放1、2、4、8
{
for(int j = V; j >= k*c[i] ; --j)
dp[j] = max(dp[j],dp[j-k*c[i]] + k*a[i]);
}
k = count[i] - k;
for(int j = V; j >= k*c[i]; --j)
dp[j] = max(dp[j],dp[j-k*c[i]] + k*a[i]);
}
现在dp[i]用来表示容量为i的背包能否被所给物品恰好装满,01背包和完全背包都一样
memset(dp,false,sizeof(dp));
dp[0] = true;
for(int i = 1; i <= N; ++i)
{
memset(used,0,sizeof(used));
for(int j = c[i]; j <= V; ++j)
{
if(!dp[j] && dp[j-c[i]] && used[j-c[i]] < count[i])
{
dp[j] = true;
used[j] = used[j-c[i]] + 1;
}
}
}
混合背包
就是结合上面3种,有的物品只能取一次,有的物品能取无限次,有的物品能取有限次,枚举每个物品,判断是什么类型的背包就用什么方法写。
二维费用背包(多维同理)
比如:每件物品都有各自的体积v[i]和重量w[i],一个背包最多可以装的体积为V,最多可以装的重量为W,问最多能装的价值。就是多了一个限制
以01背包为例:
for(int i = 1; i <= n; ++i)
{
for(int j = V; j >= v[i]; --j)
{
for (int k=W; k >= w[i]; --k)
dp[j][k] = max(dp[j][k],dp[j-v[i]][k-w[i]]+a[i]);
}
}
分组背包
将n个物品分成若干组,每组只能拿一个,求最大价值
for 所有的组k
for v=V..0
for 所有的i属于组k
dp[v]=max{dp[v],dp[v-c[i]]+a[i]}