Reputation: 573
Right now, to enumerate all k=4 combinations among the set
Set = [1; 2; 3; 4; 5; 6; 7; 8]
I use the prebuilt Matlab function nchoosek that compute the binomial coefficients. The number of combinations of n things taken k at a time is computed by n!/((n–k)! k!).
Now, imagine that I have a set of data containing n = 8 elements:
Set = [1.A; 2.B; 3.C; 4.D; 5.B; 6.D; 7.C; 8.A]
I want to enumerate all the combinations of 4 integers in "Set", but with a twist: I must have only one element with the same letter in any combination (the order doesn't matter). For example:
[1.A; 2.B; 6.D; 7.C] would be a valid combination, but not [1.A; 2.B; 6.D; 8.A].
Having [1.A; 2.B; 6.D; 7.C], I must still generate the combination [8.A; 2.B; 6.D; 7.C]
Instead of having to generate 70 combinations, since there are 2 occurrences of A, B, C and D, I only have to generate 2*2*2*2 = 16 combinations. The 70-16 = 54 other combinations are irrelevant to my problem and I would rather not generate them since it becomes increasingly computationally expansive. For the moment, I generate the 70 combinations, then use some logic to remove the all the non relevant combinations.
So, my questions are:
Upvotes: 3
Views: 282
Reputation: 23955
A general recursive (iterative if stacked) algorithm:
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 example:
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,[]);
Upvotes: 1
Reputation: 21086
This is just the standard C(N, K) with a uniquness check. The below code is JavaScript but converting it to C++ shouldn't be too difficult.
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');
note If you're K's are very large you may want to use a Set (HashSet) implementation for the combo variable instead of just an array.
Upvotes: 1
Reputation: 1126
Your twist adds a constraint to the problem. As far as I know there is no special name for this new problem, it is just a combinatorics problem like any other.
Notice that what you have ultimately done is add choices for each possible "slot" in the result set. The underlying assumption for the regular choose formula is that a given item can be either in the set, or not in the set. Notice that for each group A, B, C, and D, either
OR
Thus selecting which types of integers will be in the result set is the analog of selecting the actual integers that were in the result set of the original problem! Once we select which types of integers are in the result set, we can just make any choice for which integer of each type we will put into the set.
In your case, if we must choose 4 types to put into the set then the number of ways to do that is 4 choose 4 = 1 (A,B,C,D). For type A there are 2 options, type B there are 2 options, type C there are 2 options and type D there are 2 options, so there are 2*2*2*2=16 sets to choose :)
Upvotes: 1
Reputation: 80187
Transform you set to the form
[A[1, 8], B[2,5], C[3,7], D[4,6]]
Generate base combinations by letter key - here is only one (C(4,4)) base combination (A,B,C,D) and expand combinations with number subkeys (for example, with recursive approach)
Upvotes: 2