Hendrik
Hendrik

Reputation: 3

Complex permutation/combination

Abstract:
You select the modules you are registered for.
Each module has a number of groups.
Each group represents lectures for the given module.
Each combination should contain only one group from each module.

Example:
COS 121 -3 Groups
COS 132 -2 Groups

This will give you 6 options: [1,1],[1,2],[2,1],[2,2],[3,1],[3,2]

My angle: I need to use each combination to generate the timetable, so I use an array which stores the current group being used and the total number of groups: arrSubjects[subject,currentGroup,maxGroups]

Logically you should be able to iterate through this array to make use of each combination of groups.

I just can't get the grasp of this solution, maybe because I'm using the wrong angle. Any help/suggestions would really be appreciated.

My current implementation: I'm quite embarrassed about this, because it takes a lot of time, but it works. Here's the basic in pseudo-code:

for (all the groups multiplied with eachother) do {
  for (all the modules selected) do {
    Select a random group between 1 and the nmr of groups 
  }
}

After which I have to get rid of all the duplicates.

Thanks in advance

The code I'm currently working on:

arrPermutations[0,0]:=1;//Current group for 1st module
arrPermutations[0,1]:=3;//Max groups for 1st module
arrPermutations[1,0]:=1;
arrPermutations[1,1]:=3;
arrPermutations[2,0]:=1;//Current group for 3rd module
arrPermutations[2,1]:=3;//Max groups for 3rd module
iCurrent:=iMax; //2
while (arrPermutations[0,0]<=arrPermutations[0,1]) do
begin
//Display arrPermutations
if arrPermutations[iCurrent,0]=arrPermutations[iCurrent,1] then
begin
  Inc(arrPermutations[iCurrent-1,0]);
  for i := iCurrent to iMax do
    arrPermutations[i,0]:=1;
  iCurrent:=iMax;
end else
begin
  Inc(arrPermutations[iCurrent,0]);
end;
end;

Currently I'm only traversing through the last two groups. Here's the output I get when checking:
============Run 1==============
module,current group,max groups
1,1,3
2,1,3
3,1,3
============Run 2==============
module,current group,max groups
1,1,3
2,1,3
3,2,3
============Run 3==============
module,current group,max groups
1,1,3
2,1,3
3,3,3
============Run 4==============
module,current group,max groups
1,1,3
2,2,3
3,1,3
============Run 5==============
module,current group,max groups
1,1,3
2,2,3
3,2,3
============Run 6==============
module,current group,max groups
1,1,3
2,2,3
3,3,3
============Run 7==============
module,current group,max groups
1,1,3
2,3,3
3,1,3
============Run 8==============
module,current group,max groups
1,1,3
2,3,3
3,2,3
============Run 9==============
module,current group,max groups
1,1,3
2,3,3
3,3,3
============Run 10==============//////Here is the problem
module,current group,max groups
1,1,3
2,4,3
3,1,3

Upvotes: 0

Views: 806

Answers (1)

Chris Okasaki
Chris Okasaki

Reputation: 4955

NEW ANSWER:

First, the number of possible combinations is the product of the number of groups in each module. For example, if there are three modules, contaning 5, 2, and 7 groups respectively, then there are 5*2*7 = 70 possible combinations. Call this TOTALCOMBOS.

So, if you want to iterate through all the possible combinations, you can just loop from 0 to TOTALCOMBOS-1.

for I in 0..TOTALCOMBOS-1 do
    COMBO = (convert I to a combination)
    (do something with COMBO)

Now, to convert the index into a combination, it helps to think of the integer index as a list of "digits" from right to left. This is easiest to see if there are ten groups per module, and if group numbers start at 0 instead of 1. Then an integer 468 could be read as the list (8,6,4), which means group 8 from module 1, group 6 from module 2, and group 4 from module 3. In pseudocode, converting an index to a combination would be something like

DIGITS = I
for M in 1..(number of modules) do
   D = DIGITS mod (number of groups in module M)
   DIGITS = DIGITS / (number of groups in module M)
   (add group D from module M to the current combination)

If you want group numbers to start at 1 instead of 0, then just use group D+1 in the last line, instead of group D.

OLD ANSWER:

Use recursion. The recursive function can take a list of modules, and return a list of combinations. Each combination will contain one group from each module in the input list.

As the base case, if the list of modules is empty, return an empty list of combinations.

Otherwise, let M be the first module, and let REST be the rest of the modules. Call the recursive function on REST to get all combinations of the rest of the modules (call this list of combinations COMBOS). Note that these combinations in COMBOS do not contain groups from M.

Now, we'll make a list of all the combinations, this time including the groups from M. Initialize a list ANSWERS to empty. Use two nested loops. For each group G in M, and for each combination C in COMBOS, add G to C, and add this extended combination to ANSWERS.

Return ANSWERS.

(Assumptions: No group appears in more than one module, or in the same module twice. No module appears in the list of modules more than once. You can relax these assumptions if you want, but you would need to define what you wanted the behavior to be in these cases.)

(Comment 1: I said "list" above, but all these lists could just as easily be arrays or some other kind of container.)

(Comment 2: Where I said "add G to C", it is important that C itself not be changed, because it will be re-used many times, once for each group in M.)

Upvotes: 1

Related Questions