【问题标题】:Binomial coefficient with a twist扭曲的二项式系数
【发布时间】:2015-08-18 18:29:12
【问题描述】:

现在,枚举集合中的所有 k=4 个组合

Set = [1; 2; 3; 4; 5; 6; 7; 8]

我使用预构建的 Matlab 函数 nchoosek 来计算二项式系数。一次取 k 的 n 个事物的组合数由 n!/((n–k)!k!) 计算。

现在,假设我有一组包含 n = 8 个元素的数据:

Set = [1.A; 2.B; 3.C; 4.D; 5.B; 6.D; 7.C; 8.A]

我想枚举“Set”中 4 个 整数 的所有组合,但有一个转折点:在任何组合中,我必须只有一个元素具有相同的 letter (顺序无关紧要)。例如:

[1.A; 2.B; 6.D; 7.C] 将是一个有效的组合,但不是 [1.A; 2.B; 6.D; 8.A]。

有 [1.A; 2.B; 6.D; 7.C],我仍然必须生成组合 [8.A; 2.B; 6.D; 7.C]

不必生成 70 个组合,因为 A、B、C 和 D 出现了 2 次,所以我只需要生成 2*2*2*2 = 16 个组合。 70-16 = 54 其他组合与我的问题无关,我宁愿不生成它们,因为它的计算量越来越大。目前,我生成了 70 个组合,然后使用一些逻辑来删除所有不相关的组合。

所以,我的问题是:

  1. 是否有此类组合的名称? (可以帮助我搜索信息并更好地了解问题)
  2. 是否有一些现有的算法允许计算?在 Matlab 或 C++ 中。请,如果它充满了reg ex,欢迎提供一些解释......

【问题讨论】:

  • 所以您要计算存在多少个集合?或者您是否希望生成集合以进行进一步处理?
  • 我正在寻找两者,但主要是为了生成所有集合以供进一步处理......

标签: c++ algorithm matlab


【解决方案1】:

变换你设置的形式

[A[1, 8], B[2,5], C[3,7], D[4,6]]

通过字母键生成基本组合 - 这里只有一个 (C(4,4)) 基本组合 (A,B,C,D) 并使用数字子键扩展组合(例如,使用递归方法)

【讨论】:

    【解决方案2】:

    通用递归(如果堆叠则迭代)算法:

    combs(index,multiset,k,result):
      if length of result == k:
        output result
        return
      if length of result + length of multiset - index < k:
        return
      for j in multiset[index]:
        combs(index + 1,multiset,k,result with multiset[index][j] added)
      combs(index + 1,multiset,k,result)
    

    JavaScript 示例:

    function combs(i,multiset,k,result){
      if (result.length == k){
        console.log(result);
        return;
      }
      if (result.length + multiset.length - i < k)
        return;
      for (var j=0; j<multiset[i].length; j++){
        _result = result.slice();
        _result.push(multiset[i][j]);
        combs(i + 1,multiset,k,_result);
      }
      combs(i + 1,multiset,k,result);
    }
    
    combs(0,[["1.A","8.A"],["2.B","5.B"],["3.C","7.C"],["4.D","6.D"]],4,[]);
    

    【讨论】:

    • 是否有一个非递归的通用算法?
    • @Doombot 一种方法可能是将调用堆叠在函数内部,您首先调用myCurrentParameters = stack.pop(),对myCurrentParameters 执行操作,然后不调用myFunction(param1,param2,param3...),而是推送下一个配置/s到堆栈stack.push(param1,param2,param3...)。您可以枚举堆叠参数中的数组索引/指针,而不是实际的元素列表,以使其尽可能高效。我现在想不出一种直接的方法来迭代这些组合,尽管这听起来很有趣。
    • 好的,我试图找到一种直接的方法来解决它,因为我对 Matlab 中的递归函数不是那么好。但我担心这是不可能的,无论如何如果没有硬编码的东西是不可能的,比如字母的数量(A、B、C、D - 4 个字母等)
    【解决方案3】:

    你的扭曲增加了问题的约束。据我所知,这个新问题没有特殊的名称,它只是一个与其他问题一样的组合问题。

    请注意,您最终所做的是为结果集中的每个可能的“槽”添加选项。常规选择公式的基本假设是给定项目可以在集合中,也可以不在集合中。请注意,对于每个组 A、B、C 和 D,要么

    1. 该类型的单个整数在结果集中,

    1. 该类型的整数根本不在集合中

    因此,选择将在结果集中包含哪些类型整数类似于选择原始问题结果集中的实际整数!一旦我们选择了结果集中的整数类型,我们就可以选择将每种类型的整数放入集合中。

    在您的情况下,如果我们必须选择 4 种类型放入集合中,那么方法的数量是 4 选择 4 = 1 (A,B,C,D)。 A型有2个选项,B型有2个选项,C型有2个选项,D型有2个选项,所以有2*2*2*2=16套可供选择:)

    【讨论】:

      【解决方案4】:

      这只是带有唯一性检查的标准 C(N, K)。下面的代码是 JavaScript,但将其转换为 C++ 应该不会太难。

      function nchoosekUnique(arr, k, combo, result) {
        if(combo.length === k) {
          result.push(combo);
          return result;
        }
        for(var i=0; i < arr.length - k; i++) {
          // UNIQUE CHECK
          var unique = true;
          for(var u=0; u<combo.length; u++) {
            if(combo[u][1] == arr[i][1]) { 
              unique = false; 
              continue; 
            }
          }
          //
          if(unique === true) {
            var comboCpy = combo.slice(0);
            var arrCpy = arr.slice(0);
            comboCpy[comboCpy.length] = arrCpy.splice(i, 1)[0];
            nchoosekUnique(arrCpy, k, comboCpy, result);
          }
        }
        return result;
      }
      
      var arr = [[1,"A"], [2,"B"], [3,"C"], [4,"D"], [5,"B"], [6,"D"], [7,"C"], [8,"A"]];
      JSON.stringify(nchoosekUnique(arr, 4, [], []), null, '\t');
      

      注意如果您的 K 非常大,您可能希望对组合变量使用 Set (HashSet) 实现,而不仅仅是一个数组。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多