Skip to content

Instantly share code, notes, and snippets.

@olligobber
Last active March 30, 2020 07:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save olligobber/9ac88131e83a80db45fed4cd0ba1e79d to your computer and use it in GitHub Desktop.
Save olligobber/9ac88131e83a80db45fed4cd0ba1e79d to your computer and use it in GitHub Desktop.
How many 1c, 7c, or 10c stamps do you need to total a given value
import qualified DP
import Data.Map ((!))
nextSubproblem :: DP.DPCalc Int Int () Int
nextSubproblem = do
this <- DP.thisSubproblem
return (this + 1)
subproblemSolver :: DP.DPCalc Int Int () Int
subproblemSolver = do
this <- DP.thisSubproblem
if this < 7 then
return this
else if this < 10 then
return (this - 6)
else do
less1 <- DP.getSolution (this-1)
less7 <- DP.getSolution (this-7)
less10 <- DP.getSolution (this-10)
return $ 1 + minimum [less1, less7, less10]
main :: IO ()
main = do
total <- readLn
let dPTable = DP.runDP (DP.DP
{ DP.subproblemSolver = subproblemSolver
, DP.nextSubproblem = nextSubproblem
, DP.firstSubproblem = 0
, DP.finalSubproblem = total
} ) ()
print $ dPTable ! total
module DP
( solutions
, thisSubproblem
, problemInput
, runDP
, getSolution
, DP(..)
, DPCalc
) where
import Data.Map.Lazy (Map)
import qualified Data.Map.Lazy as M
import Control.Monad.State (State)
import Control.Monad.State as S
data DPState i o r = DPState
{ solutions :: Map i o
, thisSubproblem :: i
, problemInput :: r
}
type DPCalc i o r x = DPState i o r -> x
data DP i o r = DP
{ subproblemSolver :: DPCalc i o r o
, nextSubproblem :: DPCalc i o r i
, firstSubproblem :: i
, finalSubproblem :: i
}
runDP :: Ord i => DP i o r -> r -> Map i o
runDP dp input = S.evalState
(runDP' (subproblemSolver dp) (nextSubproblem dp) (finalSubproblem dp))
(DPState M.empty (firstSubproblem dp) input)
runDP' :: Ord i => DPCalc i o r o -> DPCalc i o r i -> i ->
State (DPState i o r) (Map i o)
runDP' subSolver nextSub finalSub = do
this <- S.gets thisSubproblem
solns <- S.gets solutions
thisSol <- S.gets subSolver
if this == finalSub then
return $ M.insert this thisSol solns
else do
next <- S.gets nextSub
probInput <- S.gets problemInput
S.put $ DPState (M.insert this thisSol solns) next probInput
runDP' subSolver nextSub finalSub
getSolution :: Ord i => i -> DPCalc i o r o
getSolution subproblem dpstate = case M.lookup subproblem $ solutions dpstate of
Nothing -> error "Solution is not calculated yet"
Just x -> x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment