生成包含Matlab中给定集合的至少一个元素的所有组合

时间:2010-10-25 11:24:46

标签: matlab combinations

我使用combnk生成组合列表。如何生成组合子集,其中始终包含特定值。例如,对于combnk(1:10, 2)我只需要包含3和/或5的组合。有快速的方法吗?

3 个答案:

答案 0 :(得分:6)

好吧,在你的具体例子中,从集合{1,...,10}中选择两个整数,使得所选整数之一为3或5,得到9 + 9-1 = 17个已知组合,所以你可以只是列举它们。

通常,要从包含整数m的整数{1,...,n}中查找所有n-choose-k组合,这与找到(n-1)-choose-(k)相同-1)来自整数{1,...,m-1,m + 1,...,n}的组合。

在matlab中,那将是

combnk([1:m-1 m+1:n], k-1)

(即使m为1或n,此代码仍然有效。)

答案 1 :(得分:2)

对于强力解决方案,您可以使用COMBNK生成所有组合,然后使用函数ANYISMEMBER仅查找包含一个或多个子集的组合数字。以下是使用上述示例的方法:

v = 1:10;            %# Set of elements
vSub = [3 5];        %# Required elements (i.e. at least one must appear in the
                     %#   combinations that are generated)
c = combnk(v,2);     %# Find pairwise combinations of the numbers 1 through 10
rowIndex = any(ismember(c,vSub),2);  %# Get row indices where 3 and/or 5 appear
c = c(rowIndex,:);   %# Keep only combinations with 3 and/or 5

修改

对于更优雅的解决方案,它看起来像Steve,我也有类似的想法。但是,我已经推广了解决方案,因此它适用于任意数量的必需元素和v中的重复元素。函数SUBCOMBNK将查找从集合k中获取的v值的所有组合,其中至少包含集合vSub中的一个值:

function c = subcombnk(v,vSub,k)
%#SUBCOMBNK   All combinations of the N elements in V taken K at a time and
%#   with one or more of the elements in VSUB as members.

  %# Error-checking (minimal):

  if ~all(ismember(vSub,v))
    error('The values in vSub must also be in v.');
  end

  %# Initializations:

  index = ismember(v,vSub);  %# Index of elements in v that are in vSub
  vSub = v(index);           %# Get elements in v that are in vSub
  v = v(~index);             %# Get elements in v that are not in vSub
  nSubset = numel(vSub);     %# Number of elements in vSub
  nElements = numel(v);      %# Number of elements in v
  c = [];                    %# Initialize combinations to empty

  %# Find combinations:

  for kSub = max(1,k-nElements):min(k,nSubset)
    M1 = combnk(vSub,kSub);
    if kSub == k
      c = [c; M1];
    else
      M2 = combnk(v,k-kSub);
      c = [c; kron(M1,ones(size(M2,1),1)) repmat(M2,size(M1,1),1)];
    end
  end

end

您可以针对上面的强力解决方案测试此功能,看它是否返回相同的输出:

cSub = subcombnk(v,vSub,2);
setxor(c,sort(cSub,2),'rows')   %# Returns an empty matrix if c and cSub
                                %#   contain exactly the same rows

我使用v = 1:15;vSub = [3 5];对蛮力解决方案进一步测试了此功能,N的值范围为2到15.创建的组合相同,但SUBCOMBNK明显更快如下面显示的平均运行时间(以毫秒为单位)所示:

N  | brute force | SUBCOMBNK
---+-------------+----------
2  |     1.49    |    0.98
3  |     4.91    |    1.17
4  |    17.67    |    4.67
5  |    22.35    |    8.67
6  |    30.71    |   11.71
7  |    36.80    |   14.46
8  |    35.41    |   16.69
9  |    31.85    |   16.71
10 |    25.03    |   12.56
11 |    19.62    |    9.46
12 |    16.14    |    7.30
13 |    14.32    |    4.32
14 |     0.14    |    0.59*   #This could probably be sped up by checking for
15 |     0.11    |    0.33*   #simplified cases (i.e. all elements in v used)

答案 2 :(得分:0)

只是为了改善史蒂夫的答案:在你的情况下(你想要所有3 和/或 5的组合)它将是

  • 添加3的所有k-1 / n-2组合
  • 添加5的所有k-1 / n-2组合
  • 添加3和5的所有k-2 / n-2组合

对于此类型的任何其他情况,很容易推广。