【问题标题】:Depth-first combination algorithm深度优先组合算法
【发布时间】:2014-01-08 00:00:10
【问题描述】:

假设我有以下数组:

A = [
  ['a', 'b', 'c'],
  ['d', 'e', 'f'],
  ['g', 'h'],
  ['i'],
  ['j', 'k', 'l']
]

我想找到每个数组元素与其他数组元素的所有可能组合(即“adgij”是一种可能性,但不是“abcde”)。

我可以暴力破解它,然后像这样循环所有内容(javascript):

var A = [
      ['a', 'b', 'c'],
      ['d', 'e', 'f'],
      ['g', 'h'],
      ['i'],
      ['j', 'k', 'l']
    ],
    combinations,
    newCombinations = [];

A.forEach(function(a, index) {
  newCombinations = [];

  if (index === 0) {
    newCombinations = a;
  } else {
    a.forEach(function(val){
      combinations.forEach(function(combination){
        newCombinations.push(combination + val);
      });
    });
  }

  combinations = newCombinations;
});

这种方法的问题在于它是广度优先的,所以如果我想在 n 次迭代后停止,我会得到不完整的组合。

有没有办法使用深度优先方法获得所有可能的组合?

【问题讨论】:

标签: algorithm combinations combinatorics


【解决方案1】:

一个简单的伪代码递归函数。

每个递归步骤从当前索引的数组中选择一个元素,并为下一个索引调用函数。

current 可以只是一个列表。

printAllCombinations(A, {}, 0)

printAllCombinations(A, current, index)
  if index == A.length
    print current
    return
  for each element e in A[index]
    current.addToBack(e)
    printAllCombinations(A, current, index + 1)
    current.removeLast(e)

【讨论】:

    【解决方案2】:

    我基本上已经创建了一个地图(例如 [0,0,0,0,0] 将选择列表中的所有 first 成员,而 [2,2,1,0 ,2] 将选择python 中的所有last 成员)转换为数字,然后翻译回列表。这有点棘手,但我希望我是对的:

    #!/usr/bin/env python
    import itertools
    
    def map_good_opt(good_opt, A):
        return [i[1][i[0]] for i in zip(good_opt, A)]
    
    if "__main__" == __name__:
    
        # your list of lists    
        A = [
              ['a', 'b', 'c'],
              ['d', 'e', 'f'],
              ['g', 'h'],
              ['i'],
              ['j', 'k', 'l']
            ]
    
        # this part generates all options (a bit more actually...)
        m = max(len(a) for a in A)
        print "m : %d" % m
        nums = range(m)
        print "nums: %r" % str(nums)
        opts = itertools.product(nums, repeat=len(A))       
    
        # now we have all number 00000 - 33333
        # we don't want 33333 or anything higher than len(A[i]) for each list in A 
        opts = itertools.product(nums, repeat=len(A))
        # this removes all bad options... (I hope :D)
        good_opts = [opt for opt in opts if len([i for i in range(len(A)) if (opt[i] < len(A[i]))]) == len(A)]
    
        # and we're left with the good options
        for opts in good_opts:
            print str(opt)
        print "GO: %d" % len(good_opts)
        for g in good_opts:
            print str("OPTIONS: " + str(g))
            print str("MAPPED TO: " + str(map_good_opt(g,A)))
        print "done."
    

    我这样做只是为了学习我最近在 Stackoverflow 中学到的 itertoolszip,你的问题看起来很有趣,可以在上面进行测试:) 祝你好运。

    【讨论】:

      猜你喜欢
      • 2017-04-13
      • 1970-01-01
      • 1970-01-01
      • 2015-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-13
      相关资源
      最近更新 更多