In order to find the most optimal combination, we should first calculate all combinations and then run through them to find out which ones are possible.

To calculate all combinations we have used the function below:

```
public function combinations($arrays, $i = 0) {
if (!isset($arrays[$i])) {
return [];
}
if ($i == count($arrays) - 1) {
return $arrays[$i];
}
// get combinations from subsequent arrays
$tmp = $this->combinations($arrays, $i + 1);
$result = [];
// concat each array from tmp with each element from $arrays[$i]
foreach ($arrays[$i] as $k => $v) {
foreach ($tmp as $x => $t) {
$result[] = is_array($t) ?
array_merge([$v], $t) :
[$v, $t];
}
}
return $result;
}
```

Then, we will run through each combination to check whether it is a possible combination according to the available places for a certain time slot

The first combination we encounter, of which all chosen time slots are available, will be marked as $finalCombination.

```
foreach ($combinations as $combination) {
// Check if available
$combinationOk = true;
foreach ($slotsAvailability as $slot => $amount) {
$arrayCountValues = array_count_values($combination);
if (isset($arrayCountValues[$slot]) && $arrayCountValues[$slot] > $amount) {
$combinationOk = false;
break;
}
}
if ($combinationOk) {
$finalCombination = $combination;
break;
}
}
```

This solution works perfectly for small allocation matrixes.

However, when we have a matrix with more students, we soon notice that this solution reaches its limits and already goes out of memory at 15 students.

We now have two possible solutions, to give the PHP process more memory or to look for another solution, such as the **Hungarian algorithm**.