getEnd() === null && $j2->getEnd() !== null) { return 1; } if ($j1->getEnd() === null && $j2->getEnd() === null) { return 0; } if ($j1->getEnd() !== null && $j2->getEnd() === null) { return -1; } return $j1->getEnd()->getTimestamp() <=> $j2->getEnd()->getTimestamp(); } /** * Search for a none-conflicting job that comes before a defined job * * @param JobInterface[] $jobs List of jobs * @param int $pivot Job to find the previous job to * * @return int * * @since 1.0.0 */ private static function binarySearch(array $jobs, int $pivot) : int { $lo = 0; $hi = $pivot - 1; while ($lo <= $hi) { $mid = (int) (($lo + $hi) / 2); if ($jobs[$mid]->getEnd() !== null && $jobs[$mid]->getEnd()->getTimestamp() <= $jobs[$pivot]->getStart()->getTimestamp() ) { if ($jobs[$mid + 1]->getEnd() !== null && $jobs[$mid + 1]->getEnd()->getTimestamp() <= $jobs[$pivot]->getStart()->getTimestamp() ) { $lo = $mid + 1; } else { return $mid; } } else { $hi = $mid - 1; } } return -1; } /** * Maximize the value of the job execution without overlapping jobs * * @param JobInterface[] $jobs Jobs to filter * * @return JobInterface[] * * @since 1.0.0 */ public static function solve(array $jobs) : array { $n = \count($jobs); if ($n < 2) { return $jobs; } \usort($jobs, function (\phpOMS\Algorithm\JobScheduling\JobInterface $j1, \phpOMS\Algorithm\JobScheduling\JobInterface $j2) : int { return self::sortByEnd($j1, $j2); }); $valueTable = [$jobs[0]->getValue()]; $resultTable = []; $resultTable[0] = [$jobs[0]]; for ($i = 1; $i < $n; ++$i) { $value = $jobs[$i]->getValue(); $jList = [$jobs[$i]]; $l = self::binarySearch($jobs, $i); if ($l != -1) { $value += $valueTable[$l]; $jList = \array_merge($resultTable[$l], $jList); } if ($value > $valueTable[$i - 1]) { $valueTable[$i] = $value; $resultTable[$i] = $jList; } else { $valueTable[$i] = $valueTable[$i - 1]; $resultTable[$i] = $resultTable[$i - 1]; } } return $resultTable[$n - 1]; } }