带有扭曲的二项式系数

时间:2015-08-18 18:29:12

标签: c++ algorithm matlab

现在,要枚举集合

中的所有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 整数的所有组合,但有一个转折:我必须只有一个元素具有相同的字母任意组合(顺序无关紧要)。例如:

[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种组合,因为有2次出现的A,B,C和D,我只需要生成2 * 2 * 2 * 2 = 16种组合。 70-16 = 54个其他组合与我的问题无关,我宁愿不生成它们,因为它变得越来越计算扩展。目前,我生成了70种组合,然后使用一些逻辑来删除所有不相关的组合。

所以,我的问题是:

  1. 是否有这种组合的名称? (可以帮助我搜索信息并更好地理解问题)
  2. 是否有一些现有的算法可以计算出来?在Matlab或C ++中。如果它充满了规则,请接受一些解释......

4 个答案:

答案 0 :(得分:2)

将您设置转换为表单

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

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

答案 1 :(得分:1)

您的扭曲会对问题产生约束。据我所知,这个新问题没有特别的名称,它只是一个与其他问题一样的组合问题。

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

  1. 该类型的单个整数位于结果集
  2. OR

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

      在你的情况下,如果我们必须选择4种类型进入集合,那么这样做的方式是4选择4 = 1(A,B,C,D)。对于类型A有2个选项,类型B有2个选项,类型C有2个选项,类型D有2个选项,所以有2 * 2 * 2 * 2 = 16组可供选择:)

答案 2 :(得分:1)

这只是具有单一性检查的标准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非常大,您可能希望对combo变量使用Set(HashSet)实现而不仅仅是数组。

答案 3 :(得分:1)

一般递归(迭代迭代,如果堆叠)算法:

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,[]);