给定一个元素数组(所有元素都是唯一的),给定一个总和
找到所有具有和s的子集。
对于前阵列{5,9,1,3,4,2,6,7,11,10}
总和是10
可能的子集是{10}, {6,4}, {7,3}, {5,3,2}, {6,3,1}
等。
还有更多。
还可以找到这些子集的总数。
请帮我解决这个问题..
答案 0 :(得分:2)
这是一个着名的回溯问题,可以通过递归来解决。基本上它是一种蛮力方法,其中尝试了每种可能的组合,但至少给出了3个边界条件来修剪搜索
这是算法:
到目前为止选择的元素总和的变量。
r变量用于剩余数组的总和。
M是所需的总和
k是以0开始的索引
w是给定整数的数组
Sum(k,s,r)
{
x[k]:=1; //select the current element
if(s<=M & r>=M-s & w[k]<=M-s)
then
{
if(s+w[k]==M)
then output all i [1..k] that x[i]=1
else
sum(k+1,s+w[k],r-w[k])
}
x[k]:=0 //don't select the current element
if(s<=M) & (r>=M-s) & (w[k]<=M-s)
then
{
if (M==s)
then output all i [1..k] that x[i]=1
else
sum(k+1,s,r-w[k])
}
}
我使用数组“x”来标记为解决方案选择的候选数字。在每个步骤3检查边界条件:
1. Sum of selected elements in "x" from "w" shouldn't exceed M. s<M.
2. Remaining numbers in array should be able to complete M. r>=M-s.
3. Single remaining value in w shouldn't overflow M. w[k]<=M-s.
如果任何条件失败,该分支将被终止。
答案 1 :(得分:1)
这里有一些python代码正在做你想要的。它广泛使用了itertools以便了解它你可能想看看itertools docs。
>>> import itertools
>>> vals = (5,9,1,3,4,2,6,7,11,10)
>>> combos = itertools.chain(*((x for x in itertools.combinations(vals, i) if sum(x) == 10) for i in xrange(len(vals)+1)))
>>> for c in combos: print c
...
(10,)
(9, 1)
(3, 7)
(4, 6)
(5, 1, 4)
(5, 3, 2)
(1, 3, 6)
(1, 2, 7)
(1, 3, 4, 2)
它的作用基本上是这样的:
for i in xrange(len(vals)+1)
,请执行:for x in itertools.combinations(vals, i)
if sum(x) == 10
对于每个子集大小,产生另一个生成器,因此我使用itertools.chain
将它们链接在一起,因此有一个生成器产生所有解决方案。
由于你只有一个生成器而不是一个列表,你需要在迭代它时对元素进行计数 - 或者你可以使用list(combos)
将生成器中的所有值放入一个列表中(这会消耗生成器,所以不要在之前/之后尝试迭代它。)
答案 2 :(得分:0)
既然你没有说它是否是家庭作业,我只给出一些提示:
让nums
成为您可以使用的数字数组(在您的示例中为nums = {5,9,1,3,4,2,6,7,11,10}
)
让targetSum
为您给出的总和值(在您的示例中为targetSum = 10
)
排序nums
:您不希望使用nums
targetSum
元素搜索解决方案
让S_s
为一组取自nums
的整数,其总和等于s
让R_s
成为所有S_s
您想查找R_s
(在您的示例中为R_10
)
现在,假设您有一个函数find(i, s)
,它使用从R_s
开始的nums
的子数组返回i
如果您nums[i] > s
可以停止(请记住您之前已排序nums
)
如果找到nums[i] == s
R_s = { { nums[i] } }
,请将其退回
对于您要计算j in [1 .. nums.length - 1]
的每个R_s' = find(i + j, targetSum - nums[i])
,然后将nums[i]
添加到R_s'
中的每个集合,并将其添加到您的结果R_s
}
通过实施find
并致电find(0, 10)
我希望这会有所帮助