参考問題を解くつもりが実問題を解いてしまったようだ。
bus.fs
type Age = Infant | Child | Adult
type Rate = Normal | Commuter | Welfare
type Fare = Age * Rate * int
let UNIT = 10
let roundup u f = (f / u * u) + (if f % u = 0 then 0 else u)
let applyAge (a,r,i) =
match a with
| Adult -> (a,r,i)
| _ -> (a,r,roundup UNIT (i/2))
let applyRate (a,r,i) =
match r with
| Normal -> (a,r,i)
| Commuter -> (a,r,0)
| Welfare -> (a,r,roundup UNIT (i/2))
let rec free n ps =
match (n, ps) with
| (0, _) -> ps
| (_, []) -> []
| (_, (a,r,_)::xs) -> (a,r,0)::free (n-1) xs
let partitionByAge ps =
let folder p (al,cl,il) =
match p with
| (Adult, _,_) -> (p::al, cl, il)
| (Child, _,_) -> ( al,p::cl, il)
| (Infant,_,_) -> ( al, cl,p::il)
List.foldBack folder ps ([],[],[])
let fare ps =
let (al,cl,il) =
ps
|> List.map (applyAge >> applyRate)
|> partitionByAge
let il2 =
il
|> List.sortWith (fun (_,_,x) (_,_,y) -> compare y x)
|> free (2 * List.length al)
List.append al << List.append cl <| il2
let parse (str:string) =
let toA c =
match c with
| 'A' -> Adult
| 'C' -> Child
| 'I' -> Infant
| _ -> failwith "invalid input"
let toR c =
match c with
| 'n' -> Normal
| 'p' -> Commuter
| 'w' -> Welfare
| _ -> failwith "invalid input"
let colon = str.IndexOf(':')
let f = System.Int32.Parse(str.Substring(0, colon))
str.Substring(colon+1).Split([|','|])
|> Array.map (fun s -> (toA (s.Chars 0), toR (s.Chars 1), f))
|> Array.toList
let calc = parse >> fare >> List.sumBy (fun (_,_,f) -> f)
(* for test *)
type TestResult = Success | Failure
let test target expected =
let actual = calc target
printfn "%A" (if expected = actual then Success else Failure)
[<EntryPoint>]
let main args =
test "210:Cn,In,Iw,Ap,Iw" 170
test "220:Cp,In" 110
test "230:Cw,In,Iw" 240
test "240:In,An,In" 240
test "250:In,In,Aw,In" 260
test "260:In,In,In,In,Ap" 260
test "270:In,An,In,In,Ip" 410
test "280:Aw,In,Iw,In" 210
test "200:An" 200
test "210:Iw" 60
test "220:Ap" 0
test "230:Cp" 0
test "240:Cw" 60
test "250:In" 130
test "260:Cn" 130
test "270:Ip" 0
test "280:Aw" 140
test "1480:In,An,In,In,In,Iw,Cp,Cw,In,Aw,In,In,Iw,Cn,Aw,Iw" 5920
test "630:Aw,Cw,Iw,An,An" 1740
test "340:Cn,Cn,Ip,Ap" 340
test "240:Iw,Ap,In,Iw,Aw" 120
test "800:Cw,An,Cn,Aw,Ap" 1800
test "1210:An,Ip,In,Iw,An,Iw,Iw,An,Iw,Iw" 3630
test "530:An,Cw,Cw" 810
test "170:Aw,Iw,Ip" 90
test "150:In,Ip,Ip,Iw,In,Iw,Iw,In,An,Iw,Aw,Cw,Iw,Cw,An,Cp,Iw" 580
test "420:Cn,Cw,Cp" 320
test "690:Cw,In,An,Cp,Cn,In" 1220
test "590:Iw,Iw,Cn,Iw,Aw,In,In,Ip,Iw,Ip,Aw" 1200
test "790:Cw,Cn,Cn" 1000
test "1220:In,In,An,An,In,Iw,Iw,In,In,Ip,In,An,Iw" 4590
test "570:Cw,Cn,Cp" 440
test "310:Cn,Cw,An,An,Iw,Cp,Cw,Cn,Iw" 1100
test "910:Aw,In,Iw,Iw,Iw,Iw,Iw,An,Cw,In" 2290
test "460:Iw,Cw,Cw,Cn" 590
test "240:Iw,Iw,In,Iw,In,In,Cn,In,An" 780
test "1240:In,In,In,Ap,In,Cw,Iw,Iw,Iw,Aw,Cw" 2170
test "1000:Iw,Ip,In,An,In,In,In,An,In,Iw,In,In,Iw,In,Iw,Iw,Iw,An" 5500
test "180:In,Aw,Ip,Iw,In,Aw,In,Iw,Iw,In" 330
test "440:In,Ip,Cp,Aw,Iw,In,An" 660
test "1270:Ap,In,An,Ip,In,Ip,Ip" 1270
0