Saruman's Army
『プログラミングコンテストチャレンジブック』 から
N 個の点が直線上にあります。点 i の位置は Xi です。N 個のうちいくつかの点を選び、それらの点に印を付けます。N 個のすべての点について、距離が R 以内の場所に印を付けられた点がなければなりません(自分に印が付いていれば、距離が 0 のところにあると考えます)。条件を満たすようにしながら、できるだけ印を付ける点を少なくしたいです。何個の点に印を付ける必要があるでしょうか。
書籍と同じアルゴリズムで while ループを再帰に変えただけ。
import Data.List (sort) import Test.HUnit solve :: Int -> [Int] -> Int solve r = length . mark [] 0 . sort -- (<=s+r) の地点のリストとそれ以降の地点のリストのペアについて考える -- (<=s+r) の地点のリストの末尾に印をつける -- p の地点に印をつけたら (<=p+r) の地点を除いて再び始めに戻って考える -- (<=s+r) の地点のリストが空の場合はそれ以降の地点の先頭を s にする where mark ps s xs = case span (<=s+r) xs of ([], []) -> ps ([], _) -> mark ps (head xs) xs (ys, xs') -> let p = last ys in mark (p:ps) (p+r) (dropWhile (<=p+r) xs') testSolve = runTestTT $ test [3 ~=? solve 10 [1, 7, 15, 20, 30, 50]]