多重背包——二进制优化/单调队列优化

  • 二进制优化
  • 单调队列优化

代码都是 POJ1742 的,注意,那道题二进制优化会超时。

普通的多重背包式子,物品个数限制:c[i]c[i]c[i],单个物品价值 w[i]w[i]w[i],每个物品的体积 v[i]v[i]v[i]

第一维是前 iii 个物品,第二维是背包容量。
dp[i,j]=max⁡(dp[i][j],dp[i−1][j−k∗v[i]]+k∗w[i])0≤k≤c[i]dp[i,j]=\max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i])\quad 0\le k\le c[i] dp[i,j]=max(dp[i][j],dp[i−1][j−k∗v[i]]+k∗w[i])0≤k≤c[i]

二进制优化

因为每个数都可以被表示成二进制形式。

二进制优化就是将物品的个数 c[i]c[i]c[i] 拆分成二进制形式,将多个物品捆绑成 2i2^i2i 个形式。

然后通过捆绑后的多重组合,能够组合出原来 0∼c[i]0\sim c[i]0∼c[i] 的所有选择。

i.e. 物品个数为 121212,就拆分成 1(20)+2(21)+4(22)+51(2^0)+2(2^1)+4(2^2)+51(20)+2(21)+4(22)+5,因为剩下的不足捆绑,就单独拎出来处理。

会发现这四个数就能组合出选择 0∼120\sim 120∼12 个物品的情况。

这就将第三维度枚举放的物品个数从 O(c[i])O(c[i])O(c[i]) 降到了 O(log⁡c[i])O(\log c[i])O(logc[i])。

如果将所有信息看成同阶,则复杂度为 O(n2log⁡n)O(n^2\log n)O(n2logn)。

#include <cstdio>
#include <cstring>
#define maxn 105
#define maxm 100005
int f[maxm], a[maxn], c[maxn];
int n, m;int main() {while( scanf( "%d %d", &n, &m ) ) {if( ! n and ! m ) break;for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );for( int i = 1;i <= n;i ++ ) scanf( "%d", &c[i] );memset( f, 0, sizeof( f ) );f[0] = 1;for( int i = 1;i <= n;i ++ ) {int k = 1;while( c[i] >= k ) {c[i] -= k;for( int j = m;j >= a[i] * k;j -- )f[j] |= f[j - a[i] * k];k <<= 1;}if( c[i] ) {for( int j = m;j >= a[i] * c[i];j -- )f[j] |= f[j - a[i] * c[i]];}}int ans = 0;for( int i = 1;i <= m;i ++ ) ans += f[i];printf( "%d\n", ans );}return 0;
}

单调队列优化

因为某种物品尽管有很多个,但是体积是一样的。

每次都会占用背包的 v[i]v[i]v[i] 体积。

所以如果原来背包的容量为 jjj,那么只会转移给 j+v[i],j+v[i]∗2,...,j+v[i]∗c[i]j+v[i],j+v[i]*2,...,j+v[i]*c[i]j+v[i],j+v[i]∗2,...,j+v[i]∗c[i],这些容量在 %v[i]\% v[i]%v[i] 下同余。

将背包容量 jjj,按照 %v[i]\% v[i]%v[i] 的余数分类考虑,显然两个不同的余数是不会相互转移的。

式子化地,令 a=j/v[i],b=j%v[i]⇒j=a∗v[i]+ba=j/v[i],b=j\%v[i]\Rightarrow j=a*v[i]+ba=j/v[i],b=j%v[i]⇒j=a∗v[i]+b

f[i][j]=max⁡{f[i−1][j−k∗v[i]]+k∗w[i]}⇒f[i][j]=max⁡{f[i−1][(a−k)∗v[i]+b]+k∗w[i]}f[i][j] = \max\Big\{f[i-1][j-k*v[i]]+k*w[i]\Big\}\Rightarrow f[i][j]=\max\Big\{f[i-1][(a-k)*v[i]+b]+k*w[i]\Big\}f[i][j]=max{f[i−1][j−k∗v[i]]+k∗w[i]}⇒f[i][j]=max{f[i−1][(a−k)∗v[i]+b]+k∗w[i]}

k(0≤k≤c[i])k\ (0\le k\le c[i])k (0≤k≤c[i]) 反正都是枚举的变量,不妨令 k=a−kk=a-kk=a−k

则 f[i][j]=max⁡{f[i−1][k∗v[i]+b]+(a−k)∗w[i]}f[i][j]=\max\Big\{f[i-1][k*v[i]+b]+(a-k)*w[i]\Big\}f[i][j]=max{f[i−1][k∗v[i]+b]+(a−k)∗w[i]}

整理得,f[i][j]=max⁡{f[i−1][k∗v[i]+b]−k∗w[i]}+a∗w[i](a−c[i]≤k≤a)f[i][j]=\max\Big\{f[i-1][k*v[i]+b]-k*w[i]\Big\}+a*w[i]\quad (a-c[i]\le k\le a)f[i][j]=max{f[i−1][k∗v[i]+b]−k∗w[i]}+a∗w[i](a−c[i]≤k≤a)

换种形式表达 kkk 的范围:j/v[i]−c[i]]≤k≤j/v[i]j/v[i]-c[i]]\le k\le j/v[i]j/v[i]−c[i]]≤k≤j/v[i]

是关于 jjj 的不减函数,一段区间,所以可以用单调队列优化。

时间复杂度是 O(nV)O(nV)O(nV),就没有 logloglog 了。

#include <cstdio>
#include <cstring>
#define maxn 100005
int n, m, head, tail;
int f[maxn], a[maxn], c[maxn], q[maxn];int main() {while( ~ scanf( "%d %d", &n, &m ) ) {if( ! n and ! m ) break;for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );for( int i = 1;i <= n;i ++ ) scanf( "%d", &c[i] );memset( f, 0, sizeof( f ) ); f[0] = 1;for( int i = 1;i <= n;i ++ ) {if( c[i] == 1 ) {for( int j = m;j >= a[i];j -- ) f[j] |= f[j - a[i]];continue;}if( a[i] * c[i] >= m ) {for( int j = a[i];j <= m;j ++ ) f[j] |= f[j - a[i]];continue;}for( int j = 0;j < a[i];j ++ ) {head = 1, tail = 0;for( int k = j;k <= m;k += a[i] ) {while( head <= tail and q[head] < k - a[i] * c[i] ) head ++;if( ! f[k] ) f[k] |= ( head <= tail );else q[++ tail] = k;}}}int ans = 0;for( int i = 1;i <= m;i ++ ) ans += f[i];printf( "%d\n", ans );}return 0;
}

【学习笔记】多重背包相关优化——二进制优化/单调队列优化相关推荐

  1. 【算法学习笔记】 图(四)用优先级队列优化Dijkstra算法求最短路径(邻接矩阵存储)

    优先级队列:priority_queue,经过实验之后发现默认是首先输出最大的元素,现在想让队头为最小的元素,需要进行运算符重载 此算法寻找源点到与它连接的所有顶点的最短路径 运算符重载: struc ...

  2. 多重背包:经典DP问题( 基本/二进制优化/单调队列优化 )

    目录 基本方法 **二进制优化 *****单调队列优化 多重背包问题描述:介于01背包和完全背包问题之间,每种物品的最大选取数目都是已知的. 对于一定数量( i )的物品有一个容量为( j )的背包, ...

  3. 多重背包单调队列优化思路_动态规划入门——多重背包与单调优化

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是算法与数据结构的第14篇文章,也是动态规划专题的第三篇. 在之前的文章当中,我们介绍了多重背包的二进制拆分的解法.在大多数情况下,这种 ...

  4. [Bzoj4182]Shopping(点分治)(树上背包)(单调队列优化多重背包)

    4182: Shopping Time Limit: 30 Sec  Memory Limit: 128 MB Submit: 374  Solved: 130 [Submit][Status][Di ...

  5. 多重背包单调队列优化思路_多重背包之单调队列优化理论性总结

    多重背包之单调队列优化: 若用F[j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值,并记m = min(n, j / v).放入背包的第i种物品的数目可以是:0.1.2--, ...

  6. 多重背包单调队列优化思路_多重背包问题

    题目描述: 无优化版本: int main(){int m, n;cin >> n >> m;for(int i = 1; i <= n; ++i){int v , w, ...

  7. AR学习笔记(七):阈值二值化优化与颜色分割的优化

    AR学习笔记(七):阈值二值化优化与颜色分割的优化 阈值二值化的优化 当前方案 图像预处理 阈值二值化 优化方案 otsu法 顶帽变换 分块阈值法 颜色分割的优化 当前方案 优化方案 HSV模型分割 ...

  8. 单调队列优化多重背包

    就是按照 % 体积的余数来分组,每组单调队列优化. 直接上模板好了. 1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 cons ...

  9. 吴恩达《机器学习》学习笔记十——神经网络相关(2)

    吴恩达<机器学习>学习笔记十--神经网络相关(2) 一. 代价函数 二. 反向传播算法 三. 理解反向传播算法 四. 梯度检测 五. 随机初始化 1.全部初始化为0的问题 2.随机初始化的 ...

最新文章

  1. 使用Python+Qt时解决QTreeWidget中的内容超出边界后自动隐藏的问题
  2. iOS 7 iPhone iPad应用开发技术详解
  3. Useful code snippet to parse the key value pairs in URL
  4. 九度oj题目1008:最短路径问题
  5. STL 源代码剖析 算法 stl_algo.h -- search
  6. 吴恩达机器学习编程题ex1上 单变量线性回归: (python版含题目要求、代码、注解)
  7. 自主可控计算机大会2019,荣科科技受邀参加2019自主可控计算机大会
  8. 老九门略--盗墓笔记老九门是哪九门(后附最新老九门电视剧百度云地址--不时更新)
  9. 全球及中国基因组学软件行业发展动态及前景趋势预测报告(2022-2027)
  10. 模拟qq邮箱mysql数据库_后台管理系统3.0(SrpingBoot+MySQL)界面仿QQ邮箱源代码
  11. keepalived实现服务高可用
  12. java 电子邮件客户端_java中的电子邮件客户端
  13. 麦森数 OpenJ_Bailian - 2706
  14. 室内三维物体识别与姿态估计--背景
  15. 「星火计划沙龙视频」Angel核心推荐算法及其应用探秘
  16. html 登录界面js代码,详解JS实现系统登录页的登录和验证
  17. QPE(量子相位估计)
  18. A5931三相无传感器 BLDC 风扇驱动器 IC
  19. LC39 Combination Sum
  20. 统计局:居民一天使用互联网平均时间2小时42分钟

热门文章

  1. sklearn集合算法预测泰坦尼克号幸存者
  2. java利用模板发送邮件_使用JavaMail实现发送模板邮件以及保存到发件箱
  3. axure 组件_技巧分享 | Axure后台组件制作的全过程
  4. 计算机职称 计算机二级证,国家计算机二级证书含金量有多高
  5. 伪装 php 版本号,linux伪装隐藏Nginx,PHP版本号提升服务器安全性
  6. java打包拆包_[Java] Java 打包成jar包 和 解压jar包
  7. mongodb时间范围查询少8个小时_为何要对开源mongodb数据库内核做二次开发
  8. c语言歌手预测成绩,5个裁判可以对10个歌手进行打分,计算各个歌手的最终得分排列...
  9. aop springboot 传入参数_Springboot添加AOP打印请求参数
  10. 7-25 朋友圈 (25 分)(详解+并查集的了解和应用)