【发布时间】:2011-03-01 02:37:40
【问题描述】:
给定一些数字集合(或列表),我想按照返回数字的总和确定的顺序迭代这些集合的叉积。例如,如果给定的集合是{1,2,3},{2,4},{5},那么我想按顺序检索叉积
, , 或 , ,
我不能先计算所有的叉积然后对它们进行排序,因为太多了。有没有什么巧妙的方法可以通过迭代器实现这一点?
(我正在为此使用 Perl,以防有模块可以提供帮助。)
【问题讨论】:
标签: algorithm perl set combinatorics
给定一些数字集合(或列表),我想按照返回数字的总和确定的顺序迭代这些集合的叉积。例如,如果给定的集合是{1,2,3},{2,4},{5},那么我想按顺序检索叉积
, , 或 , ,
我不能先计算所有的叉积然后对它们进行排序,因为太多了。有没有什么巧妙的方法可以通过迭代器实现这一点?
(我正在为此使用 Perl,以防有模块可以提供帮助。)
【问题讨论】:
标签: algorithm perl set combinatorics
对于两个集合 A 和 B,我们可以如下使用最小堆。
对于两个以上的集合,使用朴素算法并排序以减少到两个集合。在最好的情况下(当每个集合相对较小时发生),这需要存储 O(√#tuples) 个元组而不是 Ω(#tuples)。
这里有一些 Python 可以做到这一点。它应该相当直接地转译为 Perl。您需要来自 CPAN 的堆库并将我的元组转换为字符串,以便它们可以成为 Perl 哈希中的键。该集合也可以存储为哈希。
from heapq import heappop, heappush
def largest_to_smallest(lists):
"""
>>> print list(largest_to_smallest([[1, 2, 3], [2, 4], [5]]))
[(3, 4, 5), (2, 4, 5), (3, 2, 5), (1, 4, 5), (2, 2, 5), (1, 2, 5)]
"""
for lst in lists:
lst.sort(reverse=True)
num_lists = len(lists)
index_tuples_in_heap = set()
min_heap = []
def insert(index_tuple):
if index_tuple in index_tuples_in_heap:
return
index_tuples_in_heap.add(index_tuple)
minus_sum = 0 # compute -sum because it's a min heap, not a max heap
for i in xrange(num_lists): # 0, ..., num_lists - 1
if index_tuple[i] >= len(lists[i]):
return
minus_sum -= lists[i][index_tuple[i]]
heappush(min_heap, (minus_sum, index_tuple))
insert((0,) * num_lists)
while min_heap:
minus_sum, index_tuple = heappop(min_heap)
elements = []
for i in xrange(num_lists):
elements.append(lists[i][index_tuple[i]])
yield tuple(elements) # this is where the tuple is returned
for i in xrange(num_lists):
neighbor = []
for j in xrange(num_lists):
if i == j:
neighbor.append(index_tuple[j] + 1)
else:
neighbor.append(index_tuple[j])
insert(tuple(neighbor))
【讨论】: