接下来将n组成k部分 - 是否有人有工作算法?

时间:2011-01-10 13:04:54

标签: combinatorics

n k 部分的组成 - 我想列出n到k部分的所有可能成分 - 是否有人有算法(最好在R中)?或者知道它是否在库中?

例如,如果我有 n 立方体和 k 行李,并且想要列出行李中所有可能的立方体排列。例如有3种方法可以将2个立方体分成2个袋子:

(2, 0) (1, 1) (0, 2)

我找到了NEXCOM的算法。我在Fortran中找到了它的一个版本here(第46页),但是不要在Fortran中编码,所以真的了解发生了什么 - 有什么帮助吗?

4 个答案:

答案 0 :(得分:7)

由于我花了一些精力来阅读其他c ++解决方案的意图,这里转换为python(也作为生成器结果而不是字符串):

def weak_compositions(boxes, balls, parent=tuple()):
  if boxes > 1:
    for i in xrange(balls + 1):
      for x in weak_compositions(boxes - 1, i, parent + (balls - i,)):
        yield x
  else:
    yield parent + (balls,)

试验:

>>> for x in weak_compositions(3, 5): print x
(5, 0, 0)
(4, 1, 0)
(4, 0, 1)
(3, 2, 0)
...
(0, 1, 4)
(0, 0, 5)

答案 1 :(得分:6)

您尝试列出的内容称为 k -multicombination。问题通常以这种方式陈述:给定 n难以区分的球和 k 框,列出所有可能的方法来分配框中的所有球。此类分发的数量为:

factorial(n + k - 1) / (factorial(k - 1) * factorial(n))

有关更多背景信息,请参阅Twelve-Fold Way的方法4。

以下是枚举发行版的代码(C ++):

string & ListMultisets(unsigned au4Boxes, unsigned au4Balls, string & strOut = string ( ), string strBuild = string ( ))
{
    unsigned au4;
    if (au4Boxes > 1) for (au4 = 0; au4 <= au4Balls; au4++)
    {
        stringstream ss;
        ss << strBuild << (strBuild.size() == 0 ? "" : ",") << au4Balls - au4;
        ListMultisets (au4Boxes - 1, au4, strOut, ss.str ( ));
    }
    else
    {
        stringstream ss;
        ss << "(" << strBuild << (strBuild.size() == 0 ? "" : ",") << au4Balls << ")\n";
        strOut += ss.str ( );
    }
    return strOut;
}



int main(int argc, char * [])
{    
    cout << endl << ListMultisets (3, 5) << endl;
    return 0;
}

以上是上述程序的输出(分布在三个盒子上的5个球):

(5,0,0)
(4,1,0)
(4,0,1)
(3,2,0)
(3,1,1)
(3,0,2)
(2,3,0)
(2,2,1)
(2,1,2)
(2,0,3)
(1,4,0)
(1,3,1)
(1,2,2)
(1,1,3)
(1,0,4)
(0,5,0)
(0,4,1)
(0,3,2)
(0,2,3)
(0,1,4)
(0,0,5)

答案 2 :(得分:1)

计算组合(我忽略了术语的标准)和组合在某种意义上是等同的。在k + 1 n + knk部分的组合之间存在双向函数。所有人要做的就是为组合中的每个字母分配一个从1到n的数字,根据它们的数字对字母进行排序,然后:

  • 制作由连续字母数之间的差异组成的元组
  • 对元组的每个条目减去1,然后就可以了。

假设您的计算组合算法产生与'有序字母'的组合,那么剩下的就是一个微不足道的计算。

在Python中:

from itertools import combinations, tee 
  #see: 
  #http://docs.python.org/library/itertools.html#itertools.combinations
  #http://docs.python.org/library/itertools.html#itertools.tee

def diffed_tuple(t): # return a new tuple but where the entries are the differences # between consecutive entries of the original tuple. #make two iterator objects which yield entries from t in parallel t2, t1 = tee(t) # advance first iterator one step for x in t2: break # return a tuple made of the entries yielded by the iterators return tuple(e2 - e1 for e2, e1 in zip(t2, t1))

# --The Algorithm-- def compositions(n, k): for t in combinations(range(n+k), k+1): # yield the 'diffed tuple' but subtracting 1 from each entry yield tuple(e-1 for e in diffed_tuple(t))

答案 3 :(得分:0)

我已经将原始的NEXCOM算法翻译成结构化的Fortran和Java。 Java版本是:

public void allCombinations(final int n, final int k) {
    final int[] input = new int[k + 1];
    Boolean mtc = Boolean.FALSE;
    int t = n;
    int h = 0;
    do {
        if (mtc) {
            if (t > 1) {
                h = 0;
            }
            h++;
            t = input[h];
            input[h] = 0;
            input[1] = t - 1;
            input[h + 1]++;
        } else {
            // First permutation is always n00...0 i.e. it's a descending
            // series lexicographically.
            input[1] = n;
            for (int i = 2; i <= k; i++) {
                input[i] = 0;
            }
        }
        System.out.println(java.util.Arrays.toString(input));
        mtc = input[k] != n;
    } while (mtc);
}