【学习笔记】多重背包相关优化——二进制优化/单调队列优化
多重背包——二进制优化/单调队列优化
- 二进制优化
- 单调队列优化
代码都是 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(logc[i])O(\log c[i])O(logc[i])。
如果将所有信息看成同阶,则复杂度为 O(n2logn)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;
}
【学习笔记】多重背包相关优化——二进制优化/单调队列优化相关推荐
- 【算法学习笔记】 图(四)用优先级队列优化Dijkstra算法求最短路径(邻接矩阵存储)
优先级队列:priority_queue,经过实验之后发现默认是首先输出最大的元素,现在想让队头为最小的元素,需要进行运算符重载 此算法寻找源点到与它连接的所有顶点的最短路径 运算符重载: struc ...
- 多重背包:经典DP问题( 基本/二进制优化/单调队列优化 )
目录 基本方法 **二进制优化 *****单调队列优化 多重背包问题描述:介于01背包和完全背包问题之间,每种物品的最大选取数目都是已知的. 对于一定数量( i )的物品有一个容量为( j )的背包, ...
- 多重背包单调队列优化思路_动态规划入门——多重背包与单调优化
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是算法与数据结构的第14篇文章,也是动态规划专题的第三篇. 在之前的文章当中,我们介绍了多重背包的二进制拆分的解法.在大多数情况下,这种 ...
- [Bzoj4182]Shopping(点分治)(树上背包)(单调队列优化多重背包)
4182: Shopping Time Limit: 30 Sec Memory Limit: 128 MB Submit: 374 Solved: 130 [Submit][Status][Di ...
- 多重背包单调队列优化思路_多重背包之单调队列优化理论性总结
多重背包之单调队列优化: 若用F[j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值,并记m = min(n, j / v).放入背包的第i种物品的数目可以是:0.1.2--, ...
- 多重背包单调队列优化思路_多重背包问题
题目描述: 无优化版本: int main(){int m, n;cin >> n >> m;for(int i = 1; i <= n; ++i){int v , w, ...
- AR学习笔记(七):阈值二值化优化与颜色分割的优化
AR学习笔记(七):阈值二值化优化与颜色分割的优化 阈值二值化的优化 当前方案 图像预处理 阈值二值化 优化方案 otsu法 顶帽变换 分块阈值法 颜色分割的优化 当前方案 优化方案 HSV模型分割 ...
- 单调队列优化多重背包
就是按照 % 体积的余数来分组,每组单调队列优化. 直接上模板好了. 1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 cons ...
- 吴恩达《机器学习》学习笔记十——神经网络相关(2)
吴恩达<机器学习>学习笔记十--神经网络相关(2) 一. 代价函数 二. 反向传播算法 三. 理解反向传播算法 四. 梯度检测 五. 随机初始化 1.全部初始化为0的问题 2.随机初始化的 ...
最新文章
- 使用Python+Qt时解决QTreeWidget中的内容超出边界后自动隐藏的问题
- iOS 7 iPhone iPad应用开发技术详解
- Useful code snippet to parse the key value pairs in URL
- 九度oj题目1008:最短路径问题
- STL 源代码剖析 算法 stl_algo.h -- search
- 吴恩达机器学习编程题ex1上 单变量线性回归: (python版含题目要求、代码、注解)
- 自主可控计算机大会2019,荣科科技受邀参加2019自主可控计算机大会
- 老九门略--盗墓笔记老九门是哪九门(后附最新老九门电视剧百度云地址--不时更新)
- 全球及中国基因组学软件行业发展动态及前景趋势预测报告(2022-2027)
- 模拟qq邮箱mysql数据库_后台管理系统3.0(SrpingBoot+MySQL)界面仿QQ邮箱源代码
- keepalived实现服务高可用
- java 电子邮件客户端_java中的电子邮件客户端
- 麦森数 OpenJ_Bailian - 2706
- 室内三维物体识别与姿态估计--背景
- 「星火计划沙龙视频」Angel核心推荐算法及其应用探秘
- html 登录界面js代码,详解JS实现系统登录页的登录和验证
- QPE(量子相位估计)
- A5931三相无传感器 BLDC 风扇驱动器 IC
- LC39 Combination Sum
- 统计局:居民一天使用互联网平均时间2小时42分钟
热门文章
- sklearn集合算法预测泰坦尼克号幸存者
- java利用模板发送邮件_使用JavaMail实现发送模板邮件以及保存到发件箱
- axure 组件_技巧分享 | Axure后台组件制作的全过程
- 计算机职称 计算机二级证,国家计算机二级证书含金量有多高
- 伪装 php 版本号,linux伪装隐藏Nginx,PHP版本号提升服务器安全性
- java打包拆包_[Java] Java 打包成jar包 和 解压jar包
- mongodb时间范围查询少8个小时_为何要对开源mongodb数据库内核做二次开发
- c语言歌手预测成绩,5个裁判可以对10个歌手进行打分,计算各个歌手的最终得分排列...
- aop springboot 传入参数_Springboot添加AOP打印请求参数
- 7-25 朋友圈 (25 分)(详解+并查集的了解和应用)