【问题标题】:What algorithm can calculate the power set of a given set?什么算法可以计算给定集合的幂集?
【发布时间】:2010-05-06 06:58:41
【问题描述】:

我想根据数字的起始列表有效地生成唯一的数字组合列表。

示例开始 list = [1,2,3,4,5] 但算法应该适用于 [1,2,3...n]

result = 

[1],[2],[3],[4],[5]
[1,2],[1,3],[1,4],[1,5]
[1,2,3],[1,2,4],[1,2,5]
[1,3,4],[1,3,5],[1,4,5]
[2,3],[2,4],[2,5]
[2,3,4],[2,3,5]
[3,4],[3,5]
[3,4,5]
[4,5]

注意。我不想要重复的组合,尽管我可以接受它们,例如在上面的示例中,我真的不需要组合 [1,3,2] 因为它已经显示为 [1,2,3]

【问题讨论】:

  • 这看起来像是家庭作业,所以我将提供问题而不是答案:你知道 powerset 有多少成员吗? (请注意,如果它打算成为 powerset,那么您的列表是不完整的)这个数字是否暗示了一种枚举它们的方法? 大量提示:二进制
  • 不,不是家庭作业。这个例子是从我实际做的事情中简化的。这些数字是具有“数量”属性的对象,我想对每个可能的组合的数量求和,然后选择使用最多对象的组合,其中数量的总和在其他一些边界内,例如 > x
  • 与幂集相比,您的示例结果缺少空集、包含 4 个元素的 5 个子集、包含所有 5 个元素的子集以及集合 [2,4,5]。跨度>

标签: algorithm powerset superset


【解决方案1】:

只需将0 计数到2^n - 1 并根据计数的二进制表示打印数字。 1 表示您打印该号码,0 表示您不打印。示例:

set is {1, 2, 3, 4, 5}
count from 0 to 31:
count = 00000 => print {}
count = 00001 => print {1} (or 5, the order in which you do it really shouldn't matter)
count = 00010 => print {2}
        00011 => print {1, 2}
        00100 => print {3}
        00101 => print {1, 3}
        00110 => print {2, 3}
        00111 => print {1, 2, 3}
        ...
        11111 => print {1, 2, 3, 4, 5}

【讨论】:

  • Felicitari 提供一个不错且高效的答案!
【解决方案2】:
def power(a)
 (0..a.size).map {|x| a.combination(x).to_a}.flatten(1)
end

【讨论】:

  • 错字 - def power(a) (0..a.size).map {|x| a.combination(x).to_a}.flatten(1) 结束
  • map + flatten(1) = flat_map
  • 除了错字,这是迄今为止最好的答案。不幸的是,编辑队列似乎已满。
【解决方案3】:

您要问的内容有一个名称。它被称为power set

谷歌搜索“幂集算法”让我找到了这个recursive solution

红宝石算法

def powerset!(set)
   return [set] if set.empty?

   p = set.pop
   subset = powerset!(set)  
   subset | subset.map { |x| x | [p] }
end

幂集直觉

如果 S = (a, b, c) 那么 powerset(S) 是所有子集的集合 powerset(S) = {(), (a), (b), (c), (a,b), (a,c), (b,c), (a,b ,c)}

第一个“技巧”是尝试递归地定义

什么是停止状态?

S = ()有什么powerset(S)?

如何获得

减少一个元素的集合

考虑取出一个元素 - 在上面的例子中,取出 {c}

S = (a,b) 然后 powerset(S) = {(), (a), (b), (a,b)}

缺少什么?

powerset(S) = {(c), (a,c), (b,c), (a,b,c)}

注意到有什么相似之处吗?再看看……

powerset(S) = {(), (a), (b), (c), (a,b), (a,c), (b,c), ( a,b,c)}

取出任何元素

powerset(S) = {(), (a), (b), (c), (a,b), (a,c), (b,c), ( a,b,c)}

powerset(S - {c}) = {(), (a), (b), (a,b)} 联合

{c} U powerset(S - {c}) = { (c), (a,c), (b,c), (a,b,c)}

powerset(S) = powerset(S - {ei}) U ({ei } U powerset(S - {ei}))

其中 ei 是 S 的一个元素(单例)

伪算法

  1. 传递的集合是否为空?完成(注意 {} 的幂集是 {{}})
  2. 如果没有,取出一个元素
    • 对集合的其余部分递归调用方法
    • 返回由联合组成的集合
      1. 没有元素的集合的幂集(来自递归调用)
      2. 相同的集合(即 2.1),但其中的每个元素都与最初取出的元素联合

【讨论】:

  • 我认为 Paul 的意思是:“传递的集合是否为空?完成”如何产生结果 { {} }?
  • 谢谢。是的,电源组是我所追求的术语。我在 C# 中做这件事,并找到了一个看起来不错的实现:stackoverflow.com/questions/343654/…
  • 谢谢。这是一个非常可行的递归解决方案(我在 Lisp 中工作)。您的链接解释得很好。
  • 此函数在完成后擦除集合。它应该被命名为powerset!,因为它是一个破坏性的操作。
  • 很好的解决方案!
【解决方案4】:

来自 OP 的评论(复制编辑):

这个例子是我实际所做的简化形式。这些数字是具有“数量”属性的对象,我想对每个可能组合的数量求和,然后选择使用最多对象的组合,其中数量之和 N 在其他一些边界内,例如 x < N < y.

你有一个优化问题。您假设处理此优化问题的正确方法是将其分解为一个枚举问题(这是您所要求的),然后是一个过滤问题(大概您知道该怎么做)。

您还没有意识到,这种解决方案仅适用于 (a) 理论分析,或 (b) 非常小的 n 值。您要求的枚举在 n 中是指数级的,这意味着您最终会得到一些在实践中需要很长时间才能运行的东西。

因此,弄清楚如何提出这样的优化问题,写一个新问题,然后编辑这个问题以指向它。

【讨论】:

    【解决方案5】:

    与 hobodave 的答案相同,但迭代更快(在 Ruby 中)。它也适用于ArraySet

    def Powerset(set)
        ret = set.class[set.class[]]
        set.each do |s|
            deepcopy = ret.map { |x| set.class.new(x) }
            deepcopy.map { |r| r << s }
            ret = ret + deepcopy
        end
        return ret
    end
    

    在我的测试中,IVlad 的方法在 Ruby 中效果不佳。

    【讨论】:

      【解决方案6】:

      用于计算方案中功率集的递归和迭代解决方案。虽然没有完全测试

      (define (power_set set)
            (cond 
              ((empty? set) (list '()))
              (else
               (let ((part_res (power_set (cdr set))))
                 (append (map (lambda (s) (cons (car set) s)) part_res) part_res)))))
      
      (define (power_set_iter set)
        (let loop ((res '(())) (s set))
          (if (empty? s)
              res
              (loop (append (map (lambda (i) (cons (car s) i)) res) res) (cdr s)))))
      

      【讨论】:

        【解决方案7】:

        Hereafter 是一个递归解决方案,类似于已经发布的解决方案。一些断言作为单元测试提供。 我没有设法使用“set” Python 类型来表示集合。当尝试像“s.add(set())”这样的表达式时,Python 说“set objects are unhashable”。

        另请参阅http://rosettacode.org/wiki/Power_set 上许多编程语言的解决方案

        def generatePowerSet(s, niceSorting = True):
            """Generate power set of a given set.
        
            The given set, as well as, return set of sets, are implemented
            as lists.
        
            "niceSorting" optionnaly sorts the powerset by increasing subset size.
            """
            import copy
        
            def setCmp(a,b):
                """Compare two sets (implemented as lists) for nice sorting"""
                if len(a) < len(b):
                    return -1
                elif len(a) > len(b):
                    return 1
                else:
                    if len(a) == 0:
                        return 0
                    else:
                        if a < b:
                            return -1
                        elif a > b:
                            return 1
                        else:
                            return 0
        
            # Initialize the power set "ps" of set "s" as an empty set                    
            ps = list()
        
            if len(s) == 0:
                ps.append(list())
            else:
        
                # Generate "psx": the power set of "sx", 
                # which is "s" without a chosen element "x"
                sx = copy.copy(s)
                x = sx.pop()
                psx = generatePowerSet(sx, False)        
        
                # Include "psx" to "ps"      
                ps.extend(psx)
        
                # Include to "ps" any set, which contains "x"
                # Such included sets are obtained by adding "x" to any subset of "sx"
                for y in psx:
                    yx = copy.copy(y)
                    yx.append(x)
                    ps.append(yx)
        
            if niceSorting:
                ps.sort(cmp=setCmp)      
        
            return ps
        
        assert generatePowerSet([]) == [[]]
        
        assert generatePowerSet(['a']) == [[], ['a']]
        
        assert generatePowerSet(['a', 'b']) == [[], ['a'], ['b'], ['a', 'b']]
        
        assert generatePowerSet(['a', 'b','c']) == [[], 
                                                    ['a'], ['b'], ['c'], 
                                                    ['a', 'b'], ['a', 'c'], ['b', 'c'],
                                                    ['a', 'b', 'c'] ]
        
        assert generatePowerSet(['a', 'b','c'], False) == [ [], 
                                                            ['a'], 
                                                            ['b'], 
                                                            ['a', 'b'], 
                                                            ['c'], 
                                                            ['a', 'c'], 
                                                            ['b', 'c'], 
                                                            ['a', 'b', 'c'] ]
        
        print generatePowerSet(range(4), True)
        

        【讨论】:

          【解决方案8】:

          我的同事用 ruby​​ 创造了一种优雅的方法。它在索引集上使用了 IVlad 的概念。

          class Array
             def select_by_index(&block)
             # selects array element by index property
               n = []
               each_with_index do |e, i|
                  if block.call(i) 
                    n << e
                  end  
               end
               n
             end
          end
          
          def pow(a)
          # power set of a
            max = (1 << a.length)
            (0...max).map { |i| a.select_by_index { |k| (1 << k) & i != 0 }}
          end
          
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-03-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多