常见的背包问题总结与优化代码(DP)
1.01背包
优化时需要注意:第二层循环是倒序,原因这里不作说明,读者自行查找.
下面上核心代码。
for(int i=1;i<=n;i++)///n物品数,m背包容量
for(int j=m;j>=w[i];j--)//w[i]物品i的重量,v[i]物品i的价值
f[j]=max(f[j],f[j-w[i]]+v[i]);
2.完全背包(每种物品次数无限的01背包)
优化时与01背包唯一不同的一点的是:第二层循环是顺序,原因这里不作说明,读者自行查找.
下面上核心代码。
for(int i=1;i<=n;i++)
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+v[i]);
3.多重背包(01背包的升级版,每个物品个数有限个)
多重背包是01背包的延伸,01背包可看作每个物品个数为1个的多重背包.
下面上核心代码。
for(int i=1;i<=n;i++)
for(int j=1;j<=p[i];j++)
for(int k=m;k>=w[i];k--)
f[k]=max(f[k],f[k-w[i]]+v[i]);
4.分组背包(每组只能选一个物品的01背包变体)
优化时是三重循环,注意循环先后层顺序。
下面上核心代码。
vector<int>p[N];//二维数组p[i][j]表示第i组的第j个物品的序号数,方便查找w[i],v[i]
int w[N],v[N],f[N],pos;//pos表示物品在那个组。
for(int i=1;i<=n;i++){
cin>>w[i]>>v[i]>>pos;
p[pos].push_back(i);
}
for(int i=1;i<=t;i++)
for(int j=v;j>=0;j--)
for(int k=0;k<p[i].size();k++)
{
int x=p[i][k];//第i组第k个物品的序号数
if(w[x]<=j) f[j]=max(f[j],f[j-w[x]]+v[x]);
}
5.混合背包(多重背包和完全背包的合体)
就是把多重与完全背包的代码合并一下,用if判断一下就好了。
下面上核心代码。
for(int i=1;i<=n;i++)
cin>>w[i]>>v[i]>>p[i];
for(int i=1;i<=n;i++){
if(!p[i]){//完全背包
for(int j=w[i];j<=m;j++)
f[j]=max(f[j],f[j-w[i]]+v[i]);
}else{ //多重背包与01背包.
for(int j=1;j<=p[i];j++)
for(int k=m;k>=w[i];k--)
f[k]=max(f[k],f[k-w[i]]+v[i]);
}
6.双条件01背包.在(01背包优化的基础上多一维)
for(int i=1;i<=n;i++)
for(int j=w1;j>=w1[i];j--)
for(int k=w2;k>=w2[i];k--)
dp[j][k]=max(dp[j][k],dp[j-w1[i]][k-w2[i]]+v[i]);
总结:01背包,多重背包,分组背包逆序。
完全背包顺序,分组背包三重循环(多的一层是遍历每组的物品,层顺序为:组数–容量–每组物品数),混合背包是多重背包和完全背包的混合体(if判断)
--------------------------------未完待续---------------------------------