MATLAB生成n个项目可以放入m个箱子的所有方法吗?

时间:2016-09-30 20:17:03

标签: matlab combinations vectorization permutation

我想找到n个项目可以在m个分箱之间拆分的所有方法。例如,对于n=3m=3,输出将是(顺序无关紧要):

[3 0 0
 0 3 0
 0 0 3
 2 1 0
 1 2 0
 0 1 2
 0 2 1
 1 0 2
 2 0 1
 1 1 1]

算法应尽可能高效,最好使用内置函数而不是for循环进行矢量化/使用。谢谢!

2 个答案:

答案 0 :(得分:7)

这应该非常有效。

它的工作原理是在 m -1整数值,可能是重合的分裂点生成实际区间[0, n ]的所有可能的分割。结果子区间的长度给出了解决方案。

例如,对于n=4m=3,在 m -1点分割区间[0,4]的一些可能方法是:

  • 00分割:这会给出长度004的子区间。
  • 01分割:这会给出长度013的子区间。
  • ...
  • 44分割:这会给出长度400的子区间。

代码:

n = 4; % number of items
m = 3; % number of bins
x = bsxfun(@minus, nchoosek(0:n+m-2,m-1), 0:m-2); % split points
x = [zeros(size(x,1),1) x n*ones(size(x,1),1)]; % add start and end of interval [0, n]
result = diff(x.').'; % compute subinterval lengths

结果按字典顺序排列。

例如,对于n = 4个分区中的m = 3项,输出为

result =
     0     0     4
     0     1     3
     0     2     2
     0     3     1
     0     4     0
     1     0     3
     1     1     2
     1     2     1
     1     3     0
     2     0     2
     2     1     1
     2     2     0
     3     0     1
     3     1     0
     4     0     0

答案 1 :(得分:1)

我想建议一个基于外部函数和accumarray的解决方案(由于repelem,它应该可以在R2015a开始工作):

n = uint8(4); % number of items
m = uint8(3); % number of bins
whichBin = VChooseKR(1:m,n).'; % see FEX link below. Transpose saves us a `reshape()` later.
result = accumarray([repelem(1:size(whichBin,2),n).' whichBin(:)],1);

其中VChooseKR(V,K)创建一个矩阵,其行是通过重复选择向量K的{​​{1}}元素而创建的所有组合。

说明:

VVChooseKR(1:m,n)的{​​{1}}输出为:

m=3

我们现在需要做的就是" histcount"每行使用正整数二进制数来获得所需的结果。第一个输出行是n=4,因为所有4个元素都在1 st bin中。第二行是 1 1 1 1 1 1 1 2 1 1 1 3 1 1 2 2 1 1 2 3 1 1 3 3 1 2 2 2 1 2 2 3 1 2 3 3 1 3 3 3 2 2 2 2 2 2 2 3 2 2 3 3 2 3 3 3 3 3 3 3 ,因为3个元素位于1 st bin中,1个位于2 nd 等中。