什么算法可以计算给定集的功率集?

时间:2010-05-06 06:58:41

标签: algorithm powerset superset

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

示例启动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]

8 个答案:

答案 0 :(得分:63)

只需将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}

答案 1 :(得分:19)

你要问的是一个名字。它被称为power set

Google搜索“power set algorithm”让我看到了recursive solution

Ruby算法

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

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

Power Set Intuition

如果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 - {e i })U({e i } U powerset (S - {e i }))

其中e i 是S(单身)的元素

伪算法

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

答案 2 :(得分:5)

def power(a)
 (0..a.size).map {|x| a.combination(x).to_a}.flatten(1)
end

答案 3 :(得分:0)

与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中运行得不好。

答案 4 :(得分:0)

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

  

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

您拥有的是优化问题。您所假设的是,解决此优化问题的正确方法是将其分解为枚举问题(这是您所要求的),然后是过滤问题(可能您知道该怎么做)。

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

因此,弄清楚如何摆出优化问题,编写一个新问题,并编辑一个问题指向它。

答案 5 :(得分:0)

用于计算方案中的功率集的递归和迭代解决方案。尚未完全测试

(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)))))

答案 6 :(得分:0)

此后是递归解决方案,类似于已发布的解决方案。一些断言提供了一种单元测试。 我没有设法使用“set”Python类型来表示集合。 Python在尝试像“s.add(set())”这样的表达时说“设置对象是不可用的”。

请参阅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)

答案 7 :(得分:0)

我的同事创造了一种优雅的红宝石制作方式。它在索引集上使用了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