E13 背包DP 多重背包 单调队列优化
E13 背包DP 多重背包 单调队列优化——信息学奥赛算法_哔哩哔哩_bilibili
$f_{i,j}$ 表示前 $i$ 种物品,背包承重不超过 $j$ 所获得的最大价值
\begin{aligned}
f_{i,j} & =\max\limits_{k=0}^{s}(f_{i-1,j-k \times w}+k \times v), \; 0 \leq j \leq W \\
f_{i,x \cdot w+y} & =\max\limits_{k=0}^{s}(f_{i-1,(x-k) \cdot w+y}+k \cdot v), \; ^{0 \leq y \leq w}_{0 \leq x \cdot w+y \leq W} \\
& =\max\limits_{k=0}^{s}(f_{i-1,(x-k) \cdot w+y}-(x-k)\cdot v+x \cdot v) \\
& =\max\limits_{k=0}^{s}(f_{i-1,(x-k) \cdot w+y}-(x-k)\cdot v)+x \cdot v \\
& =\max\limits_{p=x-s}^{x}(f_{i-1,p\cdot w+y}-p\cdot v)+x \cdot v \\
\end{aligned}
拆分背包承重:$j=x\cdot w+y$
外层枚举 $y$,内层枚举 $x$
单调队列维护前状态的最大值
因为 $0\leq k \leq s$,所以 窗口下标 $p=x-k$ 的范围:$x-s\leq p \leq x$
// 单调队列 O(n*W) #include<bits/stdc++.h> using namespace std; const int N=40005; int n,W; int f[2][N]; int main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>n>>W; for(int i=1,v,w,s; i<=n; i++){ //物品 cin>>v>>w>>s; //价值 重量 个数 for(int y=0; y<w; y++){ //背包承重拆成整加零,即x*w+y deque<int> q; for(int x=0; x*w+y<=W; x++){ //定零变整,队列维护 while(!q.empty() && q.front()<x-s) q.pop_front(); //窗口下标[x-s,x] while(!q.empty() && f[i-1&1][q.back()*w+y]-q.back()*v<f[i-1&1][x*w+y]-x*v) q.pop_back(); q.push_back(x); f[i&1][x*w+y]=(f[i-1&1][q.front()*w+y]-q.front()*v)+x*v; } } } cout<<f[n&1][W]; }
// 单调队列 O(n*W) #include<bits/stdc++.h> using namespace std; const int N=40005; int n,W; int f[N],g[N]; int main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>n>>W; for(int i=1,v,w,s; i<=n; i++){ //物品 cin>>v>>w>>s; //价值 重量 个数 memcpy(g,f,sizeof(f)); for(int y=0; y<w; y++){ //背包承重拆成整加零,即x*w+y deque<int> q; for(int x=0; x*w+y<=W; x++){ //定零变整,队列维护 while(!q.empty() && q.front()<x-s) q.pop_front(); //窗口下标[x-s,x] while(!q.empty() && g[q.back()*w+y]-q.back()*v<g[x*w+y]-x*v) q.pop_back(); q.push_back(x); f[x*w+y]=(g[q.front()*w+y]-q.front()*v)+x*v; } } } cout<<f[W]; }
// 单调队列 O(n*W) #include<bits/stdc++.h> using namespace std; const int N=40005; int n,W; int f[2][N]; int main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>n>>W; for(int i=1,v,w,s; i<=n; ++i){ cin>>v>>w>>s; for(int y=0; y<w; ++y){ deque<int> q; for(int x=y; x<=W; x+=w){ while(!q.empty() && q.front()<x-s*w) q.pop_front(); while(!q.empty() && f[i-1&1][q.back()]+(x-q.back())/w*v<f[i-1&1][x]) q.pop_back(); q.push_back(x); f[i&1][x]=f[i-1&1][q.front()]+(x-q.front())/w*v; } } } cout<<f[n&1][W]; }
浙公网安备 33010602011771号