bounty还有5天到期。回答此问题可获得+100声望奖励。jonas87希望引起更多关注此问题。
我有一个算法,可以找到从元组列表中替换出的k个元组的组合的所有唯一和的集合。每个元组包含n个正整数,这些整数的顺序很重要,元组的和被定义为元素加法。例如(1,2,3)+(4,5,6)=(5,7,9)
简单的例子,k=2和n=3:
input = [(1,0,0), (2,1,1), (3,3,2)]
solution = [(1,0,0)+(2,1,1), (1,0,0)+(3,3,2), (2,1,1)+(3,3,2), (1,0,0)+(1,0,0), (2,1,1)+(2,1,1), (3,3,2)+(3,3,2)]
solution = [(3,1,1), (4,3,2), (5,4,3), (2,0,0), (4,2,2), (6,6,4)]
在实践中,元组中的整数范围从0到50(在某些位置,它可能会受到更多的限制,如[0:2]),k增加到4个组合,元组的长度增加到5。要从中提取的元组的数量增加到一千个。
我目前拥有的算法是related question中提出的算法的改编,它比使用itertools枚举所有组合更有效(如果我们从1000个元组中绘制4个元组,则有数十亿个组合,但总和的数量将减少几个数量级),但我不知道如何将位集应用于这个问题。
# example where length of tuples n = 3:
lst = []
for x in range(0,50,2):
for y in range(0, 20, 1):
for z in range(0, 3, 1):
lst.append((x,y,z))
# this function works for any k and n
def unique_combination_sums(lst, k):
n = len(lst[0])
sums = {tuple(0 for _ in range(n))} # initialize with tuple of zeros
for _ in range(k):
sums = {tuple(s[i]+x[i] for i in range(n)) for s in sums for x in lst}
return sums
unique_combination_sums(lst, 4)
1条答案
按热度按时间hc8w905p1#
实际上,你可以将元组编码为整数。因为你提到整数的范围是
[0, 50]
,并且可能有多达5个这样的整数,所以创建了一个51^5 = 345,025,251
值的范围,这是完全可行的。要理解我们如何进行这种编码,请考虑十进制数的工作原理-
123
意味着1*100 + 2*10 + 1*1
。每个数字乘以基数(10)的某个幂,对应于它的位置。每个数字只有一种表示,因为每个数字都小于基数(10)本身。我们可以做类似的事情。我们可以选择一个足够大的基数,比如100,然后将元组中的每个值乘以基数的相应幂。举下面的例子:这项工作本身工作得很好,但是无论您使用的是整数情况下的任何底层求解器,都可能在较小的数字上表现得更好,所以我们真的应该尽可能地尝试“压缩”表示。这意味着选择尽可能小的基数。事实上,这意味着为混合基数系统选择多个基数。不需要太多细节,这意味着如果元组的一个位置只跨越一个小的整数间隔,我们不会为那些在特定元组位置不存在的值“浪费”空间。这可能看起来像什么,对于一个任意的例子:
此外,我们还可以减去元组位置上的最小值,以进一步缩小值。我们只需要记住在将值转换回元组时将适当的偏移量乘以元素数。
所有这一切都说,这里的代码就是这样做的:
这是一个装饰器--你将它应用于函数,解决了最初的基于整数的问题,它将把函数转换成一个对元组进行操作的函数。
例如,从上面链接的相关问题中取出
Kelly1
solution,我们可以装饰它,然后它将在元组上工作:以你为例:
产生:
因此,您可以选择最快的实现,根据需要调整/优化它,然后将其修饰为对元组进行操作。