アリンコの問題といた
職業プログラマがFizzBuzz書けない理由
タイトル: Ants
問題文: 長さL cmの竿の上をn匹のアリが毎秒1cmのスピードで歩いています。アリが竿の端に到達すると竿の下に落ちていきます。また、竿の上は狭くてすれ違えないので、二匹のアリが出会うと、それぞれ反対を向いて戻っていきます。各アリについて、現在の竿の左端からの距離xiはわかりますが、どちらの方向を向いているのかはわかりません。すべてのアリが竿から落ちるまでにかかる最小の時間と最大の時間をそれぞれ求めなさい。
制約: 1≦L≦106 1≦n≦106 0≦xi≦L
出典: プログラミングコンテストチャレンジブック(p.23) / 元はPOJ No.1852
むずかしいことはわからないけど、とりあえずHaskellでかいてみたよ。
distanceFromEdge :: Float -> Float -> Float distanceFromEdge l x | l < 0.0 || x < 0.0 || x > l = error "cant calc" | otherwise = if x < l * 0.5 then x else l - x ant :: Float -> [Float] -> (Float, Float) ant l [] = (l, 0) ant l (x:xs) = (minFromEdge, l - minFromEdge) where minFromEdge = min (distanceFromEdge l x) (fst (ant l xs)) ant' :: Float -> [Float] -> (Float, Float) ant' l xs = (minFromEdge, l - minFromEdge) where minFromEdge = minimum (map (distanceFromEdge l) xs) main = do putStrLn (show(ant 10.0 [5.0, 2.0, 8.0, 4.0, 1.5, 3.0])) => (1.5, 8.5)
引数が小文字Lだと|(vertical bar)と区別つかないですね。
まだHaskellのコードを読んだことがないので、"Haskellらしさ"がわからない。
なるべくその言語らしい書き方を心掛けたいけど、わからないからフワフワしてる。
distanceFromEdge
distanceFromEdge :: Float -> Float -> Float distanceFromEdge l x | l < 0.0 || x < 0.0 || l < x = error "cant calc" | otherwise = if x < l * 0.5 then x else l - x
インデントの作法がわからん。
ガード使う時って、"="の位置合わせたりするのかな。
if, elseは一行で書かないほうがいいのかな。
ant
ant :: Float -> [Float] -> (Float, Float) ant l [] = (l, 0) ant l (x:xs) = (minFromEdge, l - minFromEdge) where minFromEdge = min (distanceFromEdge l x) (fst (ant l xs))
とりあえず再帰でも使っとけばええんやろ?ちゃうの?的な安易な発想。
whereのインデントはいくつ置けばいいの。。
ant'
ant' :: Float -> [Float] -> (Float, Float) ant' l xs = (minFromEdge, l - minFromEdge) where minFromEdge = minimum (map (distanceFromEdge l) xs)
部分適用とか使ったら関数型っぽいんやろ?ちゃうの?的な安易な発想。
感想
インデントと改行の作法を求めて旅に出ます。