我想定义一个函数,当给定一组(正整数)和一个整数时,该函数将该整数的分区数返回到该元素的元素中。例如,
partitions({1,2,3},5)=5
自1+1+1+1+1=5
,1+1+1+2=5
,1+2+2=5
,1+1+3=5
和2+3=5
以来。
在Python中实现它的最有效方法是什么?
注意:它不需要返回实际的分区,只需返回它们的数量。
答案 0 :(得分:1)
如果值为积分且为正(因此在集{1, 2, 3, ...}
中)我们可以使用动态编程方法这里:
import numpy as np
def count_subsetsum(xs : set, s : int):
v = np.zeros(s+1, dtype=int)
v[0] = 1
for x in xs:
b = np.zeros(s+1, dtype=int)
b[:] = v[:]
for d in range(x,s+1,x):
b[d:] += v[:s-d+1]
v = b
return v[s]
这里我们考虑一个向量v
。最初,向量仅包含零,除了v[0]
等于1
(因为我们可以构造一个总和为零的总和:根本不考虑任何元素)。
现在我们将更新矢量。我们将从可迭代x
中获取值xs
,我们将"总结向量"。我们通过迭代地将v[:s-d+1]
添加到向量b
的末尾来实现此目的。 v[:s-d+1]
包含最多(和不包括)s-d-1
的所有元素。我们将其添加到b[d:]
。因此,对于向量中的所有元素,v[i]
的值将添加到b[i+d]
。我们在d
的每个倍数中为x
执行此操作。所以第一次升级我们实际上只需添加一个x
"到v
中的每个元素。第二次,我们"添加两个x
s"我们已经建立的每一笔钱。
我们对x
中的每个xs
执行此操作,最后v[s]
包含我们可以构建总和为s
的总和的所有方法。所以我们返回v[s]
。
例如:
>>> count_subsetsum({1,2,3},5)
5 # 1+1+1+1+1 1+1+1+2 1+1+3 1+2+2 2+3
>>> count_subsetsum({1,2},5)
3 # 1+1+1+1+1 1+1+1+2 1+2+2
>>> count_subsetsum({1,3},5)
2 # 1+1+1+1+1 1+1+3
>>> count_subsetsum({1,3,5},5)
3 # 1+1+1+1+1 1+1+3 5
>>> count_subsetsum({1,2,4},5)
4 # 1+1+1+1+1 1+1+1+2 1+2+2 1+4
>>> count_subsetsum({1},5)
1 # 1+1+1+1+1
(我添加了一个评论,每个例子的总和)
使用动态编程方法而不是暴力方法的优势在于它不会以指数方式扩展。以下面的查询为例:
>>> count_subsetsum({1,2,5,7,22},15921)
1746490921624
即1' 746' 490' 921' 624。即使我们设法每秒产生十亿个结果,它仍然需要1到746秒(大约半小时)。所以通常计数比枚举更快。