前言

看了 ShanLunjiaJian 关于这个问题的文章,是完全没看懂,沙东队爷的中枢神经内核配置把我偏序了。叉姐在下面提了个论文,论文找不到资源,谁搞到了可以 Q 我一份之类的拜谢了。然后找到了这个可能是阅读笔记或者是翻译的的东西,这下算是看懂了。

感觉还是很有意思,对于 DP 的状态设计、优化思路等都有很大启发,所以写一下。

(有单个物品重量限制的)Subset Sum 问题

ShanLunjiaJian 把这个叫做 Knapsack,我是要批判的,因为感觉上是带不了权的啊,这不是Knapsack!

那么描述一下这个问题:给定 \(n\) 个物品,每个物品有一个正整数重量 \(w_i\),保证 \(1\le w_i\le V\),其中 \(V\) 是所谓的重量限制。现在给一个容量 \(C\),取这些物品的一个子集,使得重量和不能超过这个容量,然后要求物品总重量的最大值,也就是让浪费的容量最小。

低论

这个问题显然有一个做法,叫做把它当作一个普通 Knapsack 问题,时间复杂度 \(\Theta(nC)\)。那么有意义的 \(C \le nV\)。所以其实上界是 \(n^2V\)。现在我们有高论!可以做到 \(\Theta(nV)\)。

高论

首先这个问题有一个经典贪心做法,叫做给所有元素从小到大排个序,然后选一个前缀使得再多选一个就会超过容量限制。这个做法当然是错的,但是可以基于它给出的这个既有选择方法去做调整,那么这样一来,剩余容量就是 \(\mathrm O(V)\) 的(如果大于 \(V\) 就一定可以再多选一个,矛盾了),很可做!

现在我们面临的问题是什么呢?我们的 DP 可能出现负数重量了(因为要支持取消选择一些原本选了的物品),这种条件下,要去维持我的剩余容量始终保持 \(\mathrm O(V)\),是有一点难度的。怎么办呢?

考虑一个直觉,是不是可以这样去操作:当试图去取消一个原先选的物品(也就是选负数)的时候,一定要让当前容量是超额的;当去选正数的时候,一定要让当前容量是不满的。考虑最优解是不是一定能用这种方式构造出来——显然是可以的。证明可以这样想,假设我从贪心生成的“基础解”开始,按照某个顺序去把它修正成最优解,是不是每一步都一定能按照上述规则操作。那么可以这样想:如果现在容量是超额的,但是不存在某个元素使得“最优解中没选它,当前解中选了它”,那么最优解选择的集合一定包含当前解,它的容量就一定也是超额的,矛盾,所以一定有办法去进行操作。反之亦然,因此按照这样的规则操作,必然能得到某种最优解。更棒的是,在这样操作的过程中,剩余容量始终在 \([-V, V]\) 以内!真是好极了,接下来只需要基于这种构造方案来 DP 就可以了。

先设计一个朴素 DP。设贪心得到的分界点为 \(p\),使得目前选择的集合是标号 \(\le p\) 的物品,\(S_0 = \sum\limits_{i = 1}^{p} w_i\)。那么设 \(g_{i, j, k}\) 表示右边决策到 \(i\),左边决策到 \(j\),当前剩余容量为 \(k \in [-V, V]\) 的方案是否存在。这个 DP 复杂度是 \(\Theta(n^2V)\),真是一点优化效果都没有!但是这个东西的进一步改造非常方便,这就是下一步的想法。

注意到这是一个值为 Boolean 类型的 DP,如果发现某一维具有单调性,那么就可以压缩掉这维。可以观察到:如果 \(g_{i, j, k} = 1\),那么对于任何 \(t \le j\),都有 \(g_{i, t, k} = 1\)——毕竟在左侧做出更多决策一定不会使可达集合变小。那么可以设 \(f_{i, k} = \max\{0 \le j \le p | g_{i, j, k} = 1\}\)。如果不存在这样的 \(j\),设为 \(-1\)。那么 DP 的初始条件是 \(f_{p+1, S_0} = p\)。转移如下:

\[\begin{cases}
f_{i+1, k + w_i} \gets f_{i, k}, & k \le 0 & (1)\\
f_{i+1, k} \gets f_{i, k}, & \text{any} & (2)\\
f_{i, k - w_t} \gets t - 1; & k \ge 0 \land t \le f_{i, k} & (3)
\end{cases}
\]

整体按照 \(i\) 递增转移,每个 \(i\) 按照 \(k\) 递减的方向做转移 (3) 即可。时间复杂度是 \(\Theta(n^2V)\),真是一点优化效果都没有!但是这个 DP 已经是 2D-1D 的了,进一步改造非常方便,这就是下一步的想法。

注意到只有转移 (3) 的复杂度不对,而这个转移很大程度上是重复的——某些转移过程,在 \(i = a\) 可以做,在 \(i = a - 1\) 同样可以做。那么可以尝试去掉这些转移,让本质相同的转移在最小的可以进行的 \(i\) 处去进行。注意到对于某个特定的 \(k\),关于某个特定的 \(t\) 的转移能否进行,只和 \(f_{i, k}\) 是否足够大有关,而我们有单调性 \(f_{i, k} \le f_{i+1, k}\),这是因为转移 (2) 的存在。所以转移 (3) 的条件可以改为 \(k \ge 0 \land f_{i-1, k} \le t \le f_{i,k}\)。这样一来,某个特定 \(k\) 对总复杂度的贡献是 \(\mathrm O(n)\) 的,所以总复杂度就变成了 \(\Theta(nV)\)!我们成功了!

后记

有人问有什么应用?我不知道啊。这么基础的东西一定有很多应用前景吧!(心虚)

Subset Sum 问题单个物品重量限制前提下的更优算法的更多相关文章

  1. Subset sum problem

    https://en.wikipedia.org/wiki/Subset_sum_problem In computer science, the subset sum problem is an i ...

  2. 动态规划法(三)子集和问题(Subset sum problem)

      继续讲故事~~   上次讲到我们的主人公丁丁,用神奇的动态规划法解决了杂货店老板的两个找零钱问题,得到了老板的肯定.之后,他就决心去大城市闯荡了,看一看外面更大的世界.   这天,丁丁刚回到家,他 ...

  3. Partition Equal Subset Sum

    Given a non-empty array containing only positive integers, find if the array can be partitioned into ...

  4. LN : leetcode 416 Partition Equal Subset Sum

    lc 416 Partition Equal Subset Sum 416 Partition Equal Subset Sum Given a non-empty array containing ...

  5. Light OJ 1272 Maximum Subset Sum 高斯消元 最大XOR值

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u011686226/article/details/32337735 题目来源:problem=12 ...

  6. call 方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法.

    call 方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法. 注意:该函数的语法与 apply() 方法的语法几乎完全相同,唯一的区别在于,apply()方法接受的是一个参 ...

  7. 如何使用python在保留原excel格式的前提下插入/修改数据

    一.需求分析: 统计的报表中需要每日查询当天数据并追加到原有的excel后面. 因为原始excel格式已经设定好,如果使用xlwt,仅仅指定设定我们要插入的单元格的格式,原始数据的格式会被初始化. 所 ...

  8. a,b,c为3个整型变量,在不引入第四个变量的前提下写一个算法实现 a=b b=c c=a?(异或解决值互换问题)

    package com.Summer_0424.cn; /** * @author Summer * a,b,c为3个整型变量,在不引入第四个变量的前提下写一个算法实现 a=b b=c c=a? */ ...

  9. a,b为2个整型变量,在不引入第三个变量的前提下写一个算法实现 a与b的值互换

    package com.Summer_0424.cn; /** * @author Summer * a,b为2个整型变量,在不引入第三个变量的前提下写一个算法实现 a与b的值互换? */ publi ...

  10. 不修改模板的前提下修改VisualState中的某些值

    原文链接:不修改模板的前提下修改VisualState中的某些值 - 超威蓝火 UWP里有一件非常令人不爽的事,大部分控件只提供了Normal状态下的Background,Foreground,Bor ...

随机推荐

  1. CentOS 9 开局配置

    CentOS 9 开局配置 CentOS 9 发布有几年了,一直没有尝试使用,CentOS 9 有一些变动. 查看系统基础信息 # 查看系统基础信息 [root@chenby ~]# neofetch ...

  2. 使用 Istioctl 安装 istio

    使用 Istioctl 安装 istio 下载 Istio 转到 Istio 发布 页面,下载针对你操作系统的安装文件, 或用自动化工具下载并提取最新版本(Linux 或 macOS): [root@ ...

  3. pandas之读取文件

    当使用 Pandas 做数据分析的时,需要读取事先准备好的数据集,这是做数据分析的第一步.Panda 提供了多种读取数据的方法: read_csv() 用于读取文本文件 read_json() 用于读 ...

  4. Springboot一些常用注解

    Springboot启动注解 @SpringbootApplication 这个注解是Springboot最核心的注解,用在Springboot的主类上,标识这是一个Springboot应用,用来开启 ...

  5. spring事务里面开启线程插入,报错了是否会回滚?

    1.前言 一道非常有意思的面试题目.大概是这样子的,如果在一个事务中,开启线程进行插入更新等操作,如果报错了,事务是否会进行回滚 2.代码 示例1 @RequestMapping("/tes ...

  6. AspNetCore 成长杂记(一):JWT授权鉴权之生成JWT(其一)

    引子 最近不知怎么的,自从学了WebAPI(为什么是这个,而不是MVC,还不是因为MVC的Razor语法比较难学,生态不如现有的Vue等框架,webapi很好的结合了前端生态)以后,使用别人的组件一帆 ...

  7. OpenCv单模版多目标匹配

    OpenCv单模版多目标匹配 单模版匹配出现的问题 一. 关于单模版匹配,我一开始用的是光线较暗的图,结果根据模版匹配到的位置并不正确. 我后来想用阈值把图形的特征提取出来,在把模版的特征和原图的特征 ...

  8. vue 项目全局修改element-ui的样式/主题颜色

    一,安装sass 1 npm i sass sass-loader --save 二,安装element主题生成工具 // 全局安装npm i element-theme --save // 安装主体 ...

  9. Marior去除边距和迭代内容矫正用于自然文档矫正

    一.简要介绍 本文简要介绍了论文" Marior: Margin Removal and Iterative Content Rectification for Document Dewar ...

  10. 学node 之前你要知道这些

    初识nodejs   19年年底一个偶然的机会接到年会任务,有微信扫码登录.投票.弹幕等功能,于是决定用node 来写几个服务,结果也比较顺利.   当时用看了下koa2的官方文档,知道怎么连接数据库 ...