【问题标题】:Generating all combinations containing at least one element of a given set in Matlab在Matlab中生成包含给定集合中至少一个元素的所有组合
【发布时间】:2011-04-30 04:02:50
【问题描述】:

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

【问题讨论】:

  • 如果你不太受性能限制,你可以暴力破解,即创建大量组合,然后只选择好的组合。

标签: matlab combinations


【解决方案1】:

好吧,在您的具体示例中,从集合 {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,此代码仍然有效。)

【讨论】:

    【解决方案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 将查找从集合 v 中提取的所有 k 值组合,其中至少包括集合 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)
    

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-09
        • 2019-12-20
        • 1970-01-01
        • 2019-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多