01背包:
有N件物品和一个容量为V的背包。(每件物品只有一件)第i件物品的费用是c[i],价值是v[i],求解将哪些物品装入背包使总价值最大。
转移方程:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]},可以优化只用一维数组.
代码如下:
for(int i=0;i<nPack;i++)
for(int j=nMaxVolume;j>=w[i];j--)
if(record[j-c[i]]+v[i]>record[j])
record[j]=record[j-c[i]]+v[i];
完全背包:
如果物品不计个数,即每个物品有无穷多件的话,稍微改一下代码即可。
for(int i=0;i<nPack;i++)
for(int j=w[i];j<=nMaxVolume;j++)
if(record[j-c[i]]+v[i]>record[j])
record[j]=record[j-c[i]]+v[i];
多重背包:
每个物品给出确定的件数,求可以得到的最大价值。
for(i=0;i<kind;i++)
for(j=0;j<bag[i];j++)
for(k=nManVolume;k>=v[i];k--)
if(record[j-c[i]]+v[i]>record[j])
record[j]=record[j-c[i]]+v[i];
优化版本:
//0-1背包,代价为cost,获得的价值为weight
void ZeroOnePack(int cost,int weight)
{
for(int i=nValue;i>=cost;i--)
dp[i]=max(dp[i],dp[i-cost]+weight);
}
//完全背包,代价为cost,获得的价值为weight
void CompletePack(int cost,int weight)
{
for(int i=cost;i<=nValue;i++)
dp[i]=max(dp[i],dp[i-cost]+weight);
}
//多重背包
void MultiplePack(int cost,int weight,int amount)
{
if(cost*amount>=nValue) CompletePack(cost,weight);
else
{
int k=1;
while(k<amount)
{
ZeroOnePack(k*cost,k*weight);
amount-=k;
k<<=1;
}
ZeroOnePack(amount*cost,amount*weight);
}
}
混合背包:
01背包,完全背包,多重背包的混合体
for(i=0;i<n;i++)
{
if(第i件物品是01背包)
ZeroOnePack(c[i],v[i]);
else if(第i件物品是完全背包)
CompletePack(c[i],v[i]);
else if(第i件物品是多重背包)
MultiplePack(c[i],v[i]);
}
二维背包:
对于每件物品有两种不同费用,比如有n种物品,每种物品都有体积vi,重量wi,价值ti,限制体积最多为V,重量最多为W
增加了一维费用,只需要状态也增加一维即可。设f[i][x][y]表示前i件物品,付出两种代价分别为x和y时可以获得的最大价值。
f[i][x][y]=max{f[i-1][x][y],f[i-1][x-v[i]][y-w[i]]+t[i]}
for(i=0;i<n;i++)
{
for(int x=V;x>=v[i];x--)
{
for(int y=W;y>=w[i];y--)
{
f[x][y]=max(f[x-v[i]][y-w[i]]+t[i],f[x][y]);
}
}
}
分组背包:
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,
最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
for(int i=1;i<=n;i++)//有n组
for(int j=V;j>=1;j--)//从后往前遍历
for(int k=1;k<=m;k++)//第i组内的各个数据
if(j-k>=0&&dp[j]<dp[j-cost[i][k]]+value[i][k])dp[j]=dp[j-cost[i][k]]+value[i][k];//cost[i][j]表示第i组第j个物品的花费,value[i][j]表示第i组第j个物品的价值
需要注意的细节:
如果没有要求背包一定要装满,则record[i]初始化为0。如果要求一定要装满,则除了record[0]为0之外其他record[i]初始化为-INF。