01背包
特点:
给定几种物品,每种物品有且只有一个,并且有价值和体积两个属性。
考虑:
对每个物品只需要考虑放与不放两种情况。
1.不放,不需要处理。
2.放,由于不清楚之前放入的物品占据了多大的空间,所以需要枚举,将这个物品放入背包后可能占据背包空间的所以情况。
背包容量v,第i件物品的体积是c[i]
,价值是w[i]
;
状态转移方程:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
f[i-1][v]
指的是不放这件物品;
而f[i-1][v-c[i]]+w[i]]
指的是将第i件放入背包之后的总价值。
/*降维度
第二层采用逆循环
*/
for(int i=1;i<=n;i++)
{
for(int j=v;j>=c[i];j--)
{
f[j]=max(f[j],f[j-c[i]]+w[i]))
}
}
完全背包问题
特点:
给定几种物品,每种物品有无限多个,并且有价值和体积两个属性。
状态转移方程:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
/*降维度
第二层采用正循环
*/
for(int i=1;i<=n;i++)
{
for(int j=c[i];j<=v;j++)
{
f[j]=max(f[j],f[j-c[i]]+w[i]))
}
}
多重背包问题
特点:
给定几种物品,每种物品为有限多个,并且有价值和体积两个属性。
考虑:由于每种物品为有限多个,所以可以考虑分解为01背包问题。
基于二进制的思想,可以将第i种物品分解为若干件物品,可以有(c[i],w[i])+(c[i]*2,w[i]*2)+(c[i]*4,w[i]*4)等等;
例如11可以拆成1,2,4,4(最后的4是由11-(1+2+4)得来的);有这几个数随意组合可以合成1-11之间的任何数。
#include<bits/stdc++.h>
using namespace std;
int v[100],w[100];//每种物品的体积,价值
int f[100];
int main()
{
int n,m,k;//有n种物品,背包的总体积
int cnt=0;//拆分后物品总数
int x,y,c;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>x>>y>>k;//每种物品的体积,价值,个数
c=1;
while(k-c>0)
{
k-=c;
v[++cnt]=x*c;
w[cnt]=y*c;
c*=2;
}
v[++cnt]=x*k;//补充最后的差值
v[cnt]=y*k;
}
/*转化为01背包问题*/
for(int i=1;i<=cnt;i++)
{
for(int j=m;j>=v[i];j--)
{
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
cout<<f[m]<<endl;
}