I have a specific length I am trying to fill with planks. For this i need to find the best posibility of combination of planks, using as less planks as possible with the lowest leftover from the last plank. To do this i first create a tree with all possibilities. After that i flatten the array a bit, so i have all options in a single array (removing the tree aspect). As last i walk through the array to get the result with the lowest depth and the lowest leftover. The first two steps i complete by using a recursive funtion.
Problem: With a length of 5000mm and planks of 5000mm, 4000mm and 3000mm there are 7 possibilities. When i try a length of 20000mm and planks of 2450mm, 2750mm, 3000mm, 3150mm, 3600mm, 3900mm, 4000mm, 4600mm, 4900mm and 5000mm there are a couple of billion possibilities. Using my current code i exceed the 30sec limit with php. I tried looking for a good algorithm on google to solve this problem, but i can't find a possible solution.
Does anyone know a algorithm or a solution to solve this problem? I am trying to keep the calculations on a minimum to keep the speed as fast as possible.
Create tree
public function createPossibilities($lengths, $length, $depth = 1) {
$lengths = [2450, 2750, 3000, 3150, 3600, 3900, 4000, 4600, 4900, 5000]; // example array of all possible lengths
$res = []; // array with all possible results
foreach ($lengths as $l) {
$rest = $length - $l; // calculates the rest length
if ($rest > 0) // check if length is complete
$children = ['depth' => $depth, 'length' => $l, 'children' => $this->createPossibilities($lengths, $rest, ($depth +1))]; // if length is not complete, do function recursively
else
$children = ['depth' => $depth, 'length' => $l, 'leftover' => abs($rest)]; // if length is complete, add the leftover to the array
$res[] = $children;
}
return $res;
}
Flatten tree
public function flattenArray($array, &$possibilities, $str = '') {
foreach ($array as $element) {
$temp = $str;
$temp .= $element['length'] . ', '; // add length to string
if (array_key_exists('children', $element)) { // check if element has children
$this->flattenArray($element['children'], $possibilities, $temp); // do function recursively for the child
} else {
$temp = explode(', ', $temp); // explode the string into an array
array_pop($temp); // remove last empty element
$temp['depth'] = count($temp); // add the depth to the array
$temp['leftover'] = $element['leftover']; // add the leftover to the array
$possibilities[] = $temp; // add the possibility to the array
}
}
}
Get best possibility
public function getBestPossibility($options, &$liggersPerBreedte) {
$minDepth = -1;
$minLeftover = -1;
foreach ($options as $option) {
if ($option['depth'] < $minDepth || $minDepth == -1) { // check if possibility has fewest lengths
$minDepth = $option['depth']; // put min depth to this option
unset($option['depth']); // remove depth from option
$minLeftover = $option['leftover']; // put min leftover to this option
unset($optie['leftover']); // remove leftover from option
$bestPosibility = $option; // best possibility is array with lengths
} else if ($option['depth'] == $minDepth && $option['leftover'] < $minLeftover) { // check if depth is the same as min, but leftover is less
unset($option['depth']); // remove depth from option
$minLeftover = $optie['leftover']; // put min leftover to this option
unset($optie['leftover']); // remove leftover from option
$bestPosibility = $option; // best possibility is array with lengths
}
}
}
Example
$tree = createPossibilities([5000, 4000, 3000], 8000);
$possibilities = [];
$flatten = flattenArray($tree, $possibilities);
$best = getBestPossibilities($possibilities); // result: [5000, 3000]