私がこれまでに見つけたいくつかのこと。
次の関連問題の解決に専念できます。
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
提案されたスケジュールの最適性をチェックするだけでなく、最適でないスケジュールを改善できるアイテムのリストも提供します。