背包问题专项

背包问题专项

01背包问题

每种物品只能拿一个的问题称为01背包问题。

对于一维约束的情况,先正向枚举数量,再反向枚举约束条件。

核心代码:

1
2
3
4
for(int i=1;i<=n;i++)
for(int j=m;j>=v[i];j--)
if(!ans[j]||ans[j]>ans[j-v[i]]+w[i])
ans[j]=ans[j-v[i]]+w[i];

上述代码中设n为数量,m为最大重量,v[i]为第i个物品重量,w[i]为第i个物品价值。

对于二维约束的情况,只需要改用二维数组,并再加一个for即可。

核心代码:

1
2
3
4
5
for(int i=1;i<=n;i++)
for(int j=m;j>=v[i];j--)
for(int k=u;k>=p[i];k--)
if(!ans[j][k]||ans[j][k]>ans[j-v[i]][k-p[i]]+w[i])
ans[j][k]=ans[j-v[i]][k-p[i]]+w[i];

上述代码中设n为数量,m为最大重量,u为最大体积,v[i]为第i个物品重量,p[i]为第i个物品体积,w[i]为第i个物品价值。

对于更多维约束条件,可参照二维约束外推。

完全背包问题

每种物品可以拿无限个的问题称为完全背包问题。

对于一维约束的情况,先正向枚举数量,再正向枚举约束条件。(01背包是反向枚举约束条件)

核心代码:

1
2
3
4
for(int i=1;i<=n;i++)
for(int j=v[i];j<=m;j++)
if(!ans[j]||ans[j]>ans[j-v[i]]+w[i])
ans[j]=ans[j-v[i]]+w[i];

上述代码中设n为数量,m为最大重量,v[i]为第i个物品重量,w[i]为第i个物品价值。

对于二维约束的情况,只需要改用二维数组,并再加一个for即可。

核心代码:

1
2
3
4
5
for(int i=1;i<=n;i++)
for(int j=v[i];j<=m;j++)
for(int k=p[i];k<=u;k++)
if(!ans[j][k]||ans[j][k]>ans[j-v[i]][k-p[i]]+w[i])
ans[j][k]=ans[j-v[i]][k-p[i]]+w[i];

上述代码中设n为数量,m为最大重量,u为最大体积,v[i]为第i个物品重量,p[i]为第i个物品体积,w[i]为第i个物品价值。

对于更多维约束条件,可参照二维约束外推。

多重背包问题

01背包问题是每种物品只能拿一个,完全背包问题是每种物品可以拿无限个,而多重背包就是每种物品可以取一个或多个,但绝对是有限个,不可能无限取。

解决此类问题,只需把每种物品拆成单个即可。如第i种物品有j个,单个重量为v[i],价值为w[i],那就可以拆分成j的单个重量为v[i],价值为w[i]的物品。

拆单之后,即可使用01背包问题的解法来解决。

混合三种背包问题

顾名思义,混合三种背包问题就是以上三种的混合。每种物品既可能只有1个,又可能有多个,还可能有无数个。

对于该类问题,先按多重背包问题的解法,将有多个的物品全部拆单,使得混合三种背包问题简化为01背包和完全背包的混合;再正向枚举每件物品,按每件物品所属性质不同而决定采用正向枚举约束条件还是反向。

核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
for(int i=1;i<=n;i++)
if(f[i]==1)
{
for(int j=m;j>=v[i];j--)
if(!ans[j]||ans[j]>ans[j-v[i]]+w[i])
ans[j]=ans[j-v[i]]+w[i];
}
else
{
for(int j=v[i];j<=m;j++)
if(!ans[j]||ans[j]>ans[j-v[i]]+w[i])
ans[j]=ans[j-v[i]]+w[i];
}

上述代码中设n为数量,m为最大重量,v[i]为第i个物品重量,w[i]为第i个物品价值,f[i]=1表示第i个物品属于01背包,否则属于完全背包。
对于二维约束的情况,只需要改用二维数组,并再加一个for即可。
核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for(int i=1;i<=n;i++)
if(f[i]==1)
{
for(int j=m;j>=v[i];j--)
for(int k=u;k>=p[i];k--)
if(!ans[j][k]||ans[j][k]>ans[j-v[i]][k-p[i]]+w[i])
ans[j][k]=ans[j-v[i]][k-p[i]]+w[i];
}
else
{
for(int j=v[i];j<=m;j++)
for(int k=p[i];k<=u;k++)
if(!ans[j][k]||ans[j][k]>ans[j-v[i]][k-p[i]]+w[i])
ans[j][k]=ans[j-v[i]][k-p[i]]+w[i];
}

上述代码中设n为数量,m为最大重量,u为最大体积,v[i]为第i个物品重量,p[i]为第i个物品体积,w[i]为第i个物品价值,f[i]=1表示第i个物品属于01背包,否则属于完全背包。

对于更多维约束条件,可参照二维约束外推。

--It's the end.Thanks for your read.--