描述:给定物品总数\(n\),背包承重能力\(m\),物品价值\(v[i]\),物品重量\(w[i]\),求知足不超过背包承重能力的物品最大价值,每种物品只有一件。
解法:
设\(f[j]\)表示物品总重为\(j\)时,物品的最大总价值。
那么转移方程为函数
for(int i=1;i<=n;++i){//枚举物品 for(int j=m;j>=w[i];--j){//枚举物品总重 f[j]=max(f[j],f[j-w[i]]+v[i]); } }return f[m];
正确性:每次转移时\(f[j-w[i]]\)还没有被物品\(i\)尝试更新,故每一个状态最多被当前物品更新一次。优化
描述:给定物品种类数\(n\),背包承重能力\(m\),物品价值\(v[i]\),物品重量\(w[i]\),求知足不超过背包承重能力的物品最大价值,每种物品有无限件。
解法:
设\(f[j]\)表示物品总重为\(j\)时,物品的最大总价值。
那么转移方程为spa
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]); } }return f[m];
正确性:每次转移时\(f[j-w[i]]\)已经被物品\(i\)尝试更新,故每一个状态会被物品尽量多地更新(填满为止)。code
描述:给定物品种类数\(n\),背包承重能力\(m\),物品价值\(v[i]\),物品重量\(w[i]\),求知足不超过背包承重能力的物品最大价值,每种物品有\(c[i]\)件。
解法:
设\(f[j]\)表示物品总重为\(j\)时,物品的最大总价值。
那么转移方程为队列
for(int i=1;i<=n;++i){ for(int k=1;k<=c[i];++k){ for(int j=m;j>=w[i];--j){ f[j]=max(f[j],f[j-w[i]]+v[i]); } } }return f[m];
正确性:每种物品都以01背包的方式尝试更新了\(c[i]\)件。class
①二进制优化
将多重背包拆分红\(\log c[i]\)块使得这些块的组合能表达\(1~c[i]\)全部的数值。二进制
for(int i=1;i<=n;++i){ scanf("%d%d%d",&v[0],&w[0],&c[0]); for(int j=1;j<=c[0];j<<=1){ v[++cnt]=v[0]*j; w[cnt]=w[0]*j; c[0]-=j; }if(c[0]) v[++cnt]=v[0]*c[0],w[cnt]=w[0]*c[0]; }for(int i=1;i<=cnt;++i){ for(int j=m;j>=w[i];--j){ f[j]=max(f[j],f[j-w[i]]+v[i]); } }return f[m];
②单调队列优化
这个会了二进制优化就不必学了吧,背包问题用这个优化不了多少。co
描述:给定物品个数\(n\),背包承重能力\(m\),物品价值\(v[i]\),物品重量\(w[i]\),求知足不超过背包承重能力的物品最大价值,每种物品属于\(c[i]\)组,每组物品中只能选一个。
解法:
设\(f[j]\)表示物品总重\(j\)时,物品的最大总价值
那么转移方程为math
int x,p[MAXC][MAXN]; for(int i=1;i<=n;++i) scanf("%d%d%d",&v[i],&w[i],&x),p[x][++p[x][0]]=i; for(int i=1;i<=MAXC;++i){ for(int j=m;j>=0;--j){ for(int k=1;k<=p[i][0];++k){ if(w[p[i][k]]<=j) f[j]=max(f[j],f[j-w[p[i][k]]]+v[p[i][k]]); } } }
正确性:每一个组别的每件物品在互相冲突的前提下进行更新。枚举
描述:\(v[i]\)与\(w[i]\)成函数关系。
解法:按照分组背包方式枚举\(w[i]\)求解便可。
描述:每种物品可能能够屡次使用,也能够只有一个,有的能够无限使用,有的\(v[i]\)与\(w[i]\)成函数关系。 解法:分类讨论便可。