F[i][j] = max { F[i - 1] [j – k * v[i] ] + k * w[i] } (0 <= k <= m[i]) 是朴素的多重背包的转移公式
假设 v[i]为容量 w[i]为价值 no[i]为数量
a = j / v[i] 即a为i种物品最大可能使用次数。 b = j % v[i] 即不能用i种物品表达的价值。
则朴素转移公式可化为: F[i][j] = max { F[a*v[i] + b - k*v[i] ] + (a-k)*w[i] }
用 k 代替 a - k 得 F[i][j] = max { F[i-1][ k * v[i] + b] - k*[w] } + a*w[i] 其中 (k : 0 --> j /a)
单调队列就是用来算F[i][j] - a*w[i] 的最值的。
hdu 2191的 代码:
#include<iostream> #include<string.h> using namespace std; typedef struct { int x,t; }Q; int f[110]; int v[110],w[110],no[110]; Q ux[110]; int n,m; int fabs(int x) { if(x<0) return -x; return x; } int main() { int ti; int s,t; scanf("%d",&ti); while(ti--) { scanf("%d%d",&n,&m); for(int i=0;i<m;i++) scanf("%d%d%d",&v[i],&w[i],&no[i]); memset(f,0,sizeof(f)); for(int i=0;i<m;i++) { for(int j=0;j<v[i];j++) //使用当前i种物品时,不可能达到的情况,j=0~~n/v[i] { s=0; t=-1; for(int k=0;k<=(n-j)/v[i];k++)//当前i种物品可能使用次数 { int temp=f[j+k*v[i]]-k*w[i];//一下求max{f[(a-k)v+b}-(a-k)v即f[kv+j]-kv} while(ux[t].x<temp&&s<=t) t--; ux[++t].x=temp; ux[t].t=k; while(fabs(ux[t].t-ux[s].t)>no[i]&&s<=t) s++; f[j+k*v[i]]=ux[s].x+k*w[i]; } } } printf("%d\n",f[n]); } return 0; }