子集和动态规划 - 重叠子问题

Posted

技术标签:

【中文标题】子集和动态规划 - 重叠子问题【英文标题】:Subset Sum Dynamic Programming - Overlapping SubProblems 【发布时间】:2015-03-24 04:43:01 【问题描述】:

我无法弄清楚 重叠子问题 的 DP 第一个属性在哪里适合 子集和问题。但是,我了解 Optimal Substructure 部分。在执行包含和排除元素的递归解决方案时,问题在哪里重叠? 是不是因为它是一个 NP 问题,所以没有 DP 的两个属性。问题的链接是http://www.geeksforgeeks.org/dynamic-programming-subset-sum-problem/ 有人可以帮助我理解这一点。

【问题讨论】:

我建议您根本不要关心这两个属性。他们既不需要理解和编写动态编程解决方案,也不需要证明它。 @ILoveCoding 所以你的意思是上面没有这两个属性我们也可以找到一个DP解决方案吗?你在子集和的递归解决方案中看到任何重叠问题吗? 不,我想说没有必要使用这两个属性的概念(在我看来,它们无助于解决问题)。你可以证明这个解决方案的正确性,并在没有它们的情况下分析它的时间复杂度。 好的...如果我没有看到上述两个属性,我怎么知道DP可以应用于这个特定的问题? 可以用数学归纳法证明这个解法的正确性。 【参考方案1】:

让我们调用整个数字集 S = s[1], ...., s[n],目标值 k,如果有一个子集,则写为 f(X, t) = 1 X 总和为 t,否则为 0。所以我们要计算的答案是f(S, k)。

只要两个不同的数字子集具有相同的总和,并且该总和小于目标 k,您就会遇到重叠的子问题。详细地说,假设有一个子集 SI = s[i_1], ..., s[i_p] 和一个不同的子集 SJ = s[j_1], ..., s[j_q],这样总和(SI) = 总和 (SJ) = i_1 的其他数字;在从 f(S, k) 开始并选择包含 SJ 中的所有数字并且不包含索引 >= j_1 的其他数字之后,然后选择也排除下一个 j_1 - i_1 数字。

工作示例

假设 S = 3, 4, 5, 6, 11 和 k = 14。然后通过排除 11 并包括 5 和 6,我们得到子问题 f(3, 4, 3) (这将有解决方案 1)——这对应于选择 SI = 5, 6 和 i_1 = 3。或者,通过包括 11,然后排除 5 和 6,我们再次得到子问题 f( 3, 4, 3) -- 这对应于选择 SJ = 11 和 j_1 = 5。

【讨论】:

但并不总是有重叠的子问题,对吧?仅当两个不同的数字子集具有相同的总和并且该总和小于目标 k 时才会发生这种情况,正如您在回答中提到的那样,对吗? @j_random_hacker 和 Raghav。你能否解释一下这个问题的最佳子结构属性。谢谢 @SurbhiJain:如果您的第一个问题是,“是否存在不止一次遇到子问题的问题实例?”那么答案是肯定的:特别是,当没有两个子集给出相同的和时(例如,当 S 是 1, 2, 4, 8, 16, 32 时,每个数字只有 1 种方法介于 0 和 63 之间)。一个很好的思考方式是:绘制一个 n×k 顶点网格,其中 (i, j) 处的顶点对应于子问题 (s[1], ..., s[i], j ),我将其缩写为 (i, j)。现在对于每个这样的顶点 (i, j),绘制两个传入箭头:一个 ... ... 来自 (i-1, j) 和一个来自 (i-1, js[i]):每个箭头代表一个子问题,我们需要解决它才能解决子问题(i, j)。现在考虑一下:如果从其顶点有多个 outgoing 箭头,则重用子问题。实际上,从顶点 (i, j) 最多可以有 2 个出射箭头:一个水平箭头,指向 (i+1, j),一个对角箭头,指向 (i+1, j+s[i+1]) .只要存在从 (i+1, j) 到 (n, k) 的路径,或者等效地,只要存在总和的 s[i+2], ..., s[n] 的子集,前者就存在to kj:这个子集有助于“垂直”运动。 ... ... 只要存在从 (i+1, j+s[i+1]) 到 (n, k) 的路径,或者等效地,只要存在 s[i+2], ..., s[n] 之和为 k-(j+s[i+1]):注意我们可以将 s[i+1] 添加到这个集合中以获得第二个,必然不同,S 的子集,总和为 kj。因此,如果 (i, j) 的两个出边都存在,则 S 至少有 2 个子集的总和相同,即 k-j。 在没有重叠子问题的情况下,DP 并没有提供比普通递归解决方案的任何改进。但在这些情况下,它并不比普通递归差,并且在其余情况下可以成倍地更快。

以上是关于子集和动态规划 - 重叠子问题的主要内容,如果未能解决你的问题,请参考以下文章

动态规划 (DP) 中的重叠子问题是啥?

动态规划学习(Python)

算法导论笔记——第十五章 动态规划

动态规划

动态规划之最大递增子序列

动态规划(dynamic programming)(最优子问题与重叠子问题,以及与贪心的区别)