到目前为止,我发现了一些事情。
我们可以简化解决以下相关问题:
newtype Slot = Slot Int
newtype Schedule a = Schedule [(Slot, [a])]
findSchedule :: Ord a => Schedule a -> Schedule (a, Bool)
即给出已按截止日期排序的输入数据,但允许每天执行任意数量的非负数任务。通过仅标记元素是否可以及时进行调度来提供输出。
以下功能可以检查以这种格式给出的时间表是否可行,即是否仍可以在截止日期之前安排仍在时间表中的所有项目:
leftOverItems :: Schedule a -> [Int]
leftOverItems (Schedule sch) = scanr op 0 sch where
op (Slot s, items) itemsCarried = max 0 (length items - s + itemsCarried)
feasible schedule = head (leftOverItems schedule) == 0
如果我们有一个建议的候选解决方案,而所有项目都被排除在外,我们可以在线性时间内检查该候选项目是否最优,或者剩余项目中是否有任何项目可以改善解决方案。我们将这些轻型项目称为“ 最小生成树”算法中的术语
carry1 :: Ord a => Schedule a -> [Bound a]
carry1 (Schedule sch) = map (maybe Top Val . listToMaybe) . scanr op [] $ sch where
op (Slot s, items) acc = remNonMinN s (foldr insertMin acc items)
-- We only care about the number of items, and the minimum item.
-- insertMin inserts an item into a list, keeping the smallest item at the front.
insertMin :: Ord a => a -> [a] -> [a]
insertMin a [] = [a]
insertMin a (b:bs) = min a b : max a b : bs
-- remNonMin removes an item from the list,
-- only picking the minimum at the front, if it's the only element.
remNonMin :: [a] -> [a]
remNonMin [] = []
remNonMin [x] = []
remNonMin (x:y:xs) = x : xs
remNonMinN :: Int -> [a] -> [a]
remNonMinN n l = iterate remNonMin l !! n
data Bound a = Bot | Val a | Top
deriving (Eq, Ord, Show, Functor)
-- The curve of minimum reward needed for each deadline to make the cut:
curve :: Ord a => Schedule a -> [Bound a]
curve = zipWith min <$> runMin <*> carry1
-- Same curve extended to infinity (in case the Schedules have a different length)
curve' :: Ord a => Schedule a -> [Bound a]
curve' = ((++) <*> repeat . last) . curve
-- running minimum of items on left:
runMin :: Ord a => Schedule a -> [Bound a]
runMin = scanl1 min . map minWithBound . items . fmap Val
minWithBound :: Ord a => [Bound a] -> Bound a
minWithBound = minimum . (Top:)
-- The pay-off for our efforts, this function uses
-- the candidate solution to classify the left-out items
-- into whether they are definitely _not_ in
-- the optimal schedule (heavy items), or might be in it (light items).
heavyLight :: Ord a => Schedule a -> Schedule a -> ([[a]],[[a]])
heavyLight candidate leftOut =
unzip . zipWith light1 (curve' candidate) . items $ leftOut
where
light1 pivot = partition (\item -> pivot < Val item)
heavyLight
不仅检查提议的计划的最佳性,还为您提供可以改善非最佳计划的项目清单。