Subset_sum_problem中的所有子集

时间:2013-03-26 05:30:14

标签: c++ algorithm

我坚持要解决Subset_sum_problem

给定一组整数(S),需要计算其总和等于给定目标(T)的非空子集。

示例: 给定集合,S {4,8,10,16,20,22} 目标,T = 52。

约束: 集合S的元素N的数量限制为8.因此,NP时间解决方案是可接受的,因为N具有小的上限。 时间和空间的复杂性并不是真正的问题。

输出

总和恰好等于T = 52的可能子集是:

{10,20,22}

{4,10,16,22}

在Wiki和其他一些页面中给出的解决方案试图检查是否存在这样的子集(是/否)。

如上例所示,计算所有可能的子集并没有什么帮助。

link的动态编程方法提供单个此类子集 ,但我需要所有此类子集。

一种显而易见的方法是使用强力计算所有2 ^ N组合,但这将是我的最后手段。

我正在寻找一些编程示例(最好是C ++)或算法,用illutrations / examples计算这些子集?

4 个答案:

答案 0 :(得分:2)

如果N <= 8,为什么不用2 ^ n解?它只有256种可能性非常快

答案 1 :(得分:2)

当你为子集求和问题构造动态编程表时,你大部分都是这样的(取自问题中引用的维基百科文章):

Q(i,s):= Q(i - 1,s)或(xi == s)或Q(i - 1,s - xi)

这会将表格元素设置为0或1。

这个简单的公式不允许您区分可以给您1的几个案例。

但您可以将表元素设置为一个值,让您区分这些情况,如下所示:

Q(i,s):= {Q(i - 1,s)!= 0} * 1 + {xi == s} * 2 + {Q(i - 1,s - xi)!= 0} * 4

然后你可以从最后一个元素遍历表格。在每个元素处,元素值将告诉您是否从它及其方向有零个,一个或两个可能的路径。所有路径都会为您提供汇总到T的所有数字组合。这最多只有2 N

答案 2 :(得分:1)

蛮力强迫它。如果N被限制为8,则子集的总数为2 ^ 8,仅为256.它们出于某种原因给出约束。

您可以将集合包含表示为二进制字符串,其中每个元素都在集合中或集合中。然后你可以只增加你的二进制字符串(可以简单地表示为一个整数),然后使用按位&amp ;,确定哪些元素在集合中。运营商。一旦你计算了最多2 ^ N,你就知道你已经完成了所有可能的子集。

答案 3 :(得分:1)

最好的方法是使用动态编程方法。但是,动态编程只是回答你是否在你的问题中提到的子集和是否退出。

通过动态编程,您可以通过回溯输出所有解决方案。但是,生成所有有效组合的总时间复杂度仍为2 ^ n。

因此,任何比2 ^ n更好的算法几乎是不可能的。

<强> UPD : 来自@Knoothe评论: 您可以修改horowitz-sahni's算法以枚举所有可能的子集。如果有M个此类的集合,其总和等于S,那么整体时间复杂度为O(N * 2^(N/2) + MN)