如何按特定顺序生成集合的交叉乘积

时间:2011-03-01 02:37:40

标签: algorithm perl set combinatorics

给定一些数字集合(或列表),我想按照返回数字总和确定的顺序迭代这些集合的交叉乘积。例如,如果给定的集合是{1,2,3},{2,4},{5},那么我想按顺序检索交叉产品

< 3,4,5>中 < 2,4,5>中 <&-3,2,5- GT;或< 1,4,5>, < 2,2,5->中 < 1,2,5>

我无法先计算所有的交叉产品,然后对它们进行排序,因为有太多的方法。有没有聪明的方法来实现这个迭代器?

(我正在使用Perl,以防有模块可以提供帮助。)

1 个答案:

答案 0 :(得分:1)

对于两组A和B,我们可以使用min heap,如下所示。

  1. 排序A.
  2. 排序B。
  3. 将(0,0)推入具有优先级函数(i,j)的最小堆H中| - > A [i] + B [j]。打破关系更喜欢小i和j。
  4. 当H不为空时,弹出(i,j),输出(A [i],B [j]),插入(i + 1,j)和(i,j + 1)如果它们存在并且不要已经属于H.
  5. 对于两组以上,使用朴素算法并排序以得到两组。在最好的情况下(每个集合相对较小时会发生),这需要存储O(√#元组)元组而不是Ω(#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))