Without claiming that the solution given in this answer is optimized, optimal, or possesses any other great qualities, here is a greedy approach to the dvd packaging problem.
import System.Random import Data.List import Data.Ord -- F# programmers are so used to this operator, I just cannot live without it ...yet. (|>) ab = ba data Dvd = Dvd { duration :: Int, movies :: [Int] } deriving (Show,Eq) dvdCapacity = 1000 :: Int -- a dvd has capacity for 1000 time units - arbitrary unit -- the duration of a movie is between 1 and 1000 time units r = randomRs (1,1000) (mkStdGen 42) :: [Int] -- our test data set of 1000 movies, random movie durations drawn from r allMovies = zip [1..1000] (take 1000 r) allMoviesSorted = reverse $ sortBy (comparing snd) allMovies remainingCapacity dvd = dvdCapacity - duration dvd emptyDvd = Dvd { duration = 0, movies = [] } -- from the remaining movies, pick the largest one with at most maxDuration length. pickLargest remaining maxDuration = let (left,right) = remaining |> break (\ (a,b) -> b <= maxDuration) (h,t) = case right of [] -> (Nothing,[]) otherwise -> (Just (head right), right |> tail) in (h,[left, t] |> concat) -- add a track (movie) to a dvd addTrack dvd track = Dvd {duration = (duration dvd) + snd track, movies = fst track : (movies dvd) } -- pick dvd from dvds with largest remaining capacity -- and add the largest remaining fitting track greedyPack movies dvds | movies == [] = (dvds,[]) | otherwise = let dvds' = reverse $ sortBy (comparing remainingCapacity) dvds (picked,movies') = case dvds' of [] -> (Nothing, movies) (x:xs) -> pickLargest movies (remainingCapacity x) in case picked of Nothing -> -- None of the current dvds had enough capacity remaining -- tp pick another movie and add it. -> Add new empty dvd -- and run greedyPack again. greedyPack movies' (emptyDvd : dvds') Just p -> -- The best fitting movie could be added to the -- dvd with the largest remaining capacity. greedyPack movies' (addTrack (head dvds') p : tail dvds') (result,residual) = greedyPack allMoviesSorted [emptyDvd] usedDvdsCount = length result totalPlayTime = allMovies |> foldl (\ s (i,d) -> s + d) 0 optimalDvdsCount = round $ 0.5 + fromIntegral totalPlayTime / fromIntegral dvdCapacity solutionQuality = length result - optimalDvdsCount
Compared to the theoretical optimal number of dvds, it sends 4 additional dvds to this dataset.
source share