ながながとICPC2005 Regional, Tokyo の問題Fを Haskell で.O(n^2) の DP で, 基本的に foldl の2重ネストと.Cで書いた場合と比べて for 文の代わりに foldl になっているだけの違いしかない...
-- Problem F in ACM/ICPC 2005 ASIA Regional Tokyo
-- 2005/11/04 O(n^2) DP
import Control.Monad
import Debug.Trace
import List
main = getProblems >>= mapM_ (putStrLn.show.solve)
getProblems =
do
[n] <- getNums
if n==0 then return []
else do
xs <- getNums
b <- liftM (head.map read.words) getLine :: IO(Double)
[sr,sv,se,sf] <- liftM words getLine
liftM ((xs, b, read sr, read sv::Double, read se::Double, read sf::Double):) getProblems
where
getNums = liftM (map read.words) getLine :: IO([Int])
solve :: ([Int], Double, Int, Double, Double, Double) -> Double
solve (ys,b,r,v,e,f) = sl ys [(0.0,0)]
where
-- xs:rest of checkpoints, cs:best cost for already passed checkpoints
sl [] cs = fst $ head cs
sl (x:xs) cs = sl xs (best x cs:cs)
-- (best cost, current cost, current point)
best x cs = (\(bc,c,p) -> (min bc (c + cost (x-p) x),x)) $ foldl op (100000000, 0, x) cs
where
op (cbc, c, p) (bc, pos) = let
c' = c + cost (x-p) (x-pos)
in (min cbc (c'+b+bc), c', pos)
cost p q = ct p 0.0
where
ct p c = if p == q then c
else ct (p+1) (c+step p)
step p = if p < r then 1.0 / (v-f*fromIntegral(r-p))
else 1.0 / (v-e*fromIntegral(p-r))
- Newer: ことはじめ