给定数组形式的未排序整数集,找到所有可能的子集,其总和大于或等于const整数k, 例如: - 我们的集合是{1,2,3}和k = 2
可能的子集: -
{2},
{3},
{1,2},
{1,3},
{2,3},
{1,2,3}
我只能想到一个简单的算法,它列出了集合的所有子集,并检查子集的总和是否为> = k,但是它的指数算法并且列出所有子集需要O(2 ^ N)。我可以使用动态编程在多项式时间内解决它吗?
答案 0 :(得分:10)
列出所有子集将仍然是O(2^N)
,因为在最坏的情况下,您可能仍需要列出除空子集之外的所有子集。
动态编程可以帮助您计算具有sum >= K
您可以自下而上跟踪从范围[1..K]
总计到某个值的子集数。这样的方法将是O(N*K)
,这对于小K
来说是可行的。
动态编程解决方案的想法最好用一个例子来说明。考虑这种情况。假设您知道在由第一个i
元素组成的所有集合中,您知道t1
总和为2
,t2
总和为3
。假设下一个i+1
元素是4
。给定所有现有集合,我们可以通过附加元素i+1
或将其遗漏来构建所有新集合。如果我们将其删除,我们会得到t1
个子集,这些子集总和为2
和t2
个子集,总和为3
。如果我们附加它,那么我们会获得总计为t1
(2 + 4)和6
的{{1}}子集,其总和为t2
(3 + 4),并且包含一个子集只有7
总和为4.这为我们提供了总和为i+1
的子集数量,这些子集由第一个(2,3,4,6,7)
元素组成。我们会一直持续到i+1
。
在伪代码中,这看起来像这样:
N
答案 1 :(得分:6)
我可以使用动态编程在多项式时间内解决它吗?
没有。问题甚至比@amit(在评论中)提到的更难。找出是否存在与特定k相加的子集是subset-sum problem,这是NP难的。相反,你要求有多少解决方案等于特定的k,这是更加困难的P#类。此外,您确切的问题稍微困难一些,因为您不仅要计算,而且要枚举k和目标的所有可能子集< ķ。
答案 2 :(得分:1)
如果k为0,并且该集合的每个元素都是正数,那么您别无选择,只能输出每个可能的子集,因此该问题的下限是O(2 N ) - - 产生输出所需的时间。
除非你知道更多关于你没有告诉我们的价值k的信息,否则没有更快的通用解决方案来检查每个子集。