n表示物品的个数,weight[i]表示第i件物品的重,value[i]表示第i件物品的价值
V为背包容量,s[]存放最优解
一:01背包:
每件物品只有一个,只能选或者不选
for( i = 0 ; i < n ; i++)
{
for( j = V ; j >= weight[i] ; j--)
{
s[j] = Max(s[j],s[j-weight[i]]+value[i]);
}
}
二:完全背包:
每件物品有无限个
初始化时要注意:
如果要求恰好装满背包,那么在初始化时除了s[0]为0其它s[1..V]均设为-∞(求的是最大解,如果求的是最小解,则为∞)
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将s[0..V]全部设为0。
for( i = 0 ; i < n ; i++){
for( j = weight[i] ; j <= V ;j++){
s[j] = Max(s[j], s[ j - weight[i] ] + value[i] );
}
}
三:多重背包:
每件物品的个数为count[i]个
多重背包模板
#include <cstdio>
#include <memory.h>
int V,dp[100000];
inline int max(int a,int b)
{
return a>b ? a : b;
}
void ZeroOnePack(int val,int vol)
{
for(int v=V;v>=vol;v--)
dp[v]=max(dp[v],dp[v-vol]+val);
}
void CompletePack(int val,int vol)
{
for(int v=vol;v<=V;v++)
dp[v]=max(dp[v],dp[v-vol]+val);
}
void MultiplePack(int val,int vol,int num)
{
int cnt;
if(vol*num>=V) CompletePack(val,vol);
else
{
cnt=1;
while(cnt<num)
{
ZeroOnePack(val*cnt,vol*cnt);
num-=cnt;
cnt+=cnt;
}
}
ZeroOnePack(val*num,vol*num);
}
四:混合背包:
以上三种背包的混合,有的物品只能取一次,有的物品能取无限次,有的物品能取有限次
五:二维背包:
每件物品要话费两重的代价,比如我们先前考虑重量加上体积或者总物品的个数等等
初始化的问题:
如果是要求恰好装满背包,那么在初始化时除了s[0]为0其它s[1..V]均设为-∞,这样就可以保证最终得到的s[N]是一种恰好装满背包的最优解。
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。
初始化的s数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可 能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。
for( i = 0 ; i <= v ; i++){
s[i][0] = 0;
for( j = 1 ; j <= m ; j++){
s[i][j] = -1;
}
}
for( i = 0 ; i < n ; i++){
for( j = v ; j >= weight[i] ; j--){
for( k = m ; k > 0 ; k--){
if( s[j-weight[i]][k-1] != -1 ){
s[j][k] = Max(s[j][k],s[j-weight[i]][k-1]+value[i]);
}
}
}
}
六:分组背包:
有n件物品,分为若干组,每组中只能选择一件物品,问可以得到的最大价值
for( i = 0 ; i < n ; i++) //从第0组到n-1组
{
for( k = v ; k >= 0 ; k--)
{
for( j = 1 ; j <= count[i] ; j++ ) //count[i] 表示第i组的个数,j表示i组中的第几个
{
if( k >= weight[i][j] )
s[k] = Max(s[k] , value[i][j] + s[ k-weight[i][j] ] );
}
}
}