01背包:从右往左(因为只能由上一个物品的状态退出,如果从左往右则前边的保存的已是装了这件物品的值)递推,放不放此物品
完全背包:从左往右递推
多重背包:二进制拆包,或用单调队列优化(应该不考吧看的不明白QAQ)
装满背包:只把f[0]设为0
分组背包:把有依赖关系的方程一组,然后在一个阶段了分别dp不取附件,取一个,取两个(只有主次依赖)
二维费用:再加一维费用的循环
混合背包模板
#include<iostream> #include<cstdio> #include<algorithm> #define maxn 205 using namespace std; int n,m,w[maxn],v[maxn],a[maxn],dp[200005]; int main(){ cin>>n>>m; int tw,tv,ta; for(int i = 1;i <= n;i++){ scanf("%d%d%d",&tw,&tv,&ta); if(tw > m) n--; else{ w[i] = tw; v[i] = tv; a[i] = ta; } } for(int i = 1;i <= n;i++){ if(a[i] == -1){ for(int j = w[i];j <= m;j++){ dp[j] = max(dp[j],dp[j-w[i]]+v[i]); } } if(a[i] == 1){ for(int j = m;j >= w[i];j--){ dp[j] = max(dp[j],dp[j-w[i]]+v[i]); } } if(a[i] > 1){ if(a[i] * w[i] >= m){ for(int j = w[i];j <= m;j++){ dp[j] = max(dp[j],dp[j-a[i]*w[i]]+a[i]*v[i]); } continue; } int k = 1; for(;k<a[i];){ for(int j = m;j >= w[i]*k;j--){ dp[j] = max(dp[j],dp[j-w[i]*k]+v[i]*k); } a[i] -= k; k = k<<1; } for(int j = m;j >= w[i]*a[i];j--){ dp[j] = max(dp[j],dp[j-w[i]*a[i]]+v[i]*a[i]); } } } cout<<dp[m]<<endl; return 0; }
优先队列优化
#include<iostream> #include<algorithm> int n,m,dp[200005],w[205],v[205],a[205]; using namespace std; //“多重背包”通用模板 const int MAX_V = 200005; //v、n、w:当前所处理的这类物品的体积、个数、价值 //V:背包体积, MAX_V:背包的体积上限值 //f[i]:体积为i的背包装前几种物品,能达到的价值上限。 inline void pack(int f[], int V, int v, int n, int w) { if (n == 0 || v == 0) return; if (n == 1) { //01背包 for (int i = V; i >= v; --i) if (f[i] < f[i - v] + w) f[i] = f[i - v] + w; return; } if (n * v >= V - v + 1 || n == -1) { //完全背包(n >= V / v) for (int i = v; i <= V; ++i) if (f[i] < f[i - v] + w) f[i] = f[i - v] + w; return; } int va[MAX_V], vb[MAX_V]; //va/vb: 主/辅助队列 for (int j = 0; j < v; ++j) { //多重背包 int *pb = va, *pe = va - 1; //pb/pe分别指向队列首/末元素 int *qb = vb, *qe = vb - 1; //qb/qe分别指向辅助队列首/末元素 for (int k = j, i = 0; k <= V; k += v, ++i) { if (pe == pb + n) { //若队列大小达到指定值,第一个元素X出队。 if (*pb == *qb) ++qb; //若辅助队列第一个元素等于X,该元素也出队。 ++pb; } int tt = f[k] - i * w; *++pe = tt; //元素X进队 //删除辅助队列所有小于X的元素,qb到qe单调递减,也可以用二分法 while (qe >= qb && *qe < tt) --qe; *++qe = tt; //元素X也存放入辅助队列 f[k] = *qb + i * w; //辅助队列首元素恒为指定队列所有元素的最大值 } } } int main(){ cin>>n>>m; for(int i = 1;i <= n;i++){ cin>>w[i]>>v[i]>>a[i]; } for(int i = 1;i <= n;i++){ pack(dp,m,w[i],a[i],v[i]); } cout<<dp[m]; return 0; }