多重背包问题:

有N种物品和容量为V的背包,若第i种物品容量为v[i],价值为w[i],总共有n[i]件,怎样装才能使背包内的物品总价值最大?

设dp[i][j]表示对容量为j的背包,处理完前i种物品后,背包内的物品可达到的最大总价值,并设m[i] = min(n[i]. j / v[i])。

放入背包的第i种物品的数目可以是0、1、2......,可得:

dp[i][j] = max{dp[i-1][j-k*v[i]] + k*w[i]} (0 <= k <= m[i])

如何在O(1)时间内求出dp[i][j]呢?

我们先假设所有物品都只有两件,背包容量足够大,并假设dp[i][j] = dp(j) (固定i,只看j的影响), v = v[i], w = w[i];

则:

j = 6*v时, 我们需要求dp(6*v),dp(5*v)+w,dp(4*v) + 2*w这三项中的最大值;

j = 5*v时, 我们需要求dp(5*v),dp(4*v)+w,dp(3*v) + 2*w这三项中的最大值;

j = 4*v时, 我们需要求dp(4*v),dp(3*v)+w,dp(2*v) + 2*w这三项中的最大值;

稍作变形:

j = 6*v时 每项都减去6*w;

j = 5*v时 每项都减去5*w;

j = 4*v时 每项都减去4*w;

则:

j = 6*v时, 我们需要求dp(6*v) - 6*w,dp(5*v)-5*w,dp(4*v) - 4*w这三项中的最大值;

j = 5*v时, 我们需要求dp(6*v) - 5*w,dp(5*v)-4*w,dp(4*v) - 3*w这三项中的最大值;

j = 4*v时, 我们需要求dp(6*v) - 4*w,dp(5*v)-3*w,dp(4*v) - 2*w这三项中的最大值;

此时我们会发现求解最大项的过程中会有很多重复

因此可以将递推公式做一些调整:

设a = j/v[i], b = j % v[i], 既j = a * v[i] + b,将此式带入原递推方程得:

dp[i][j] = max{dp[i-1][b + (a - k)*v[i]] + k*w[i]} (0 <= k <= m[i])

用t替换(a-k)得:

dp[i][j] = max{dp[i-1][b + t*v[i]] + (a-t)*w[i]} (a - m[i] <= t <= a)

化简一下:dp[i][j] = max{dp[i-1][b + t*v[i]] -t*w[i]}  + a*w[i](a - m[i] <= t <= a)

因此,dp[i][j]就是求j的前面m[i] + 1个数对应的dp[i - 1][b + t * v[i]] - t*w[i]的最大值,加上a*w[i].

如果将dp[i][j]前面所有的dp[i - 1][b + t*v[i]] - t*w[i]放入一个队列,原问题可以转化为:

在O(1)时间内求一个队列的最大值。

这时就可以使用单调队列了,模板如下

const int maxn = 110;
const int maxv = 100000 + 10;
int N, V, n[maxn], v[maxn], w[maxn];
int dp[maxv], q1[maxv], q2[maxv];//q1存储状态,q2是单调队列void bag01(int w, int v) {for (int i = V; i >= v; i--) {dp[i] = max(dp[i], dp[i - v] + w);}
}void completebag(int w, int v) {for (int i = v; i <= V; i++) {dp[i] = max(dp[i], dp[i - v] + w);}
}void multiplybag(int w, int v, int n) {if (n == 0 || v == 0) return; //数量或价值为0都没有意义,直接忽略if (n == 1) bag01(w, v);else if (n * v >= V) completebag(w, v);else {for (int i = 0; i < v; i++) {int head1 = 0, tail1 = -1, head2 = 0, tail2 = -1;//注意队列是闭区间int cnt = 0;for (int j = i; j <= V; j += v) {if (tail1 == head1 + n) {//若队列1大小达到指定值,则第一个元素出队if (q1[head1] == q2[head2]) ++head2;//若q2的第一个元素等于q1出队的元素,则该元素也出队++head1;}int temp = dp[j] - cnt * w;q1[++tail1] = temp;while (tail2 >= head2 && q2[tail2] < temp) --tail2;//删除辅助队列q2所有小于temp的元素,使q2单调递减q2[++tail2] = temp;dp[j] = q2[head2] + cnt * w;//q2队首元素为q1所有状态的最大值cnt++;}}}
}

多重背包O(VN)算法——单调队列优化相关推荐

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

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

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

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

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

    多重背包--二进制优化/单调队列优化 二进制优化 单调队列优化 代码都是 POJ1742 的,注意,那道题二进制优化会超时. 普通的多重背包式子,物品个数限制:c[i]c[i]c[i],单个物品价值 ...

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

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

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

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

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

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

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

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

  8. 算法笔记--单调队列优化dp

    单调队列:队列中元素单调递增或递减,可以用双端队列实现(deque),队列的前面和后面都可以入队出队. 单调队列优化dp: 问题引入: dp[i] = min( a[j] ) ,i-m < j ...

  9. 提高篇 第五部分 动态规划 第5章 单调队列优化动态规划

    单调队列:是一种双端除列,其内部元素具有单调性. 最大队列 最小队列 操作: .插入:新元素插入队尾,删除除尾元素,直到找到插入后不会破坏单调性的为止. .获取最大(最小)值,访问队首元素. 单调队列 ...

最新文章

  1. Python之操作RabbitMQ
  2. 经典算法学习——冒泡排序
  3. idea install 失败_idea maven install 卡住,无报错排查。
  4. php 获得汉字拼音首字母的函数,php 获得汉字拼音首字母的函数
  5. 区块链基础语言(二)——Go语言开发环境搭建
  6. 解决问题--DatabaseMetaData的getTables()返回所有数据库的表信息
  7. Elasticsearch6.3.0环境安装
  8. ajax调用微信退款接口,微信退款(在.net core 用http方式请求)
  9. 安全工具系列 -- 信息收集(二)
  10. 什么是激励函数?(代码+详细注释)
  11. java 补丁_java SP3补丁说明
  12. 挖金矿问题(c++求解)
  13. 一鸣心所向:想成功?变身蝙蝠侠吧
  14. 读完这篇系列文章,前端offer手到擒来!!!
  15. 计算机专业的论文的格式,计算机专业毕业论文格式范例
  16. 【js】判断时间段之间是否有重叠
  17. 基于QT搭建的网易云音乐
  18. php 在线选座,基于jquery实现在线选座订座之影院篇
  19. EtherNet IP以太网IO接口工业读写器|读卡器CK-FR12-E01性能与PLC组网攻略
  20. LabVIEW编程基础:顺序结构编程

热门文章

  1. CSS实现文本溢出显示省略号
  2. JavaScript异步任务的异常处理方法
  3. 网络营销中邮件营销的优势
  4. mysql federated 缺点_mysql federated 慢
  5. 【云原生】Docker部署/容器加速器(最新版)
  6. Make Directory as
  7. 盘点疫情发生以来,那些努力在第一线的“新生战力”
  8. IntelliJ IDEA设置代码自动提示的快捷键
  9. 深入浅出游戏算法(3)-lua脚本
  10. HDMI转MIPI的实现方式