「人材獲得作戦・4 試験問題ほか」を解こうとしている(帰ってきた・未完)
ちょっと間をあけてしまったけれど d:id:i_k_b:20100117:1263720610 の続き。
昨日の朝、電車の中でロジックを考えたコード:
import Control.Monad import Data.List type Depth = Int type Cordinate = (Int, Int) type Position = (Depth, Cordinate) type Board = [String] type State = (Position, Board) main :: IO () main = do input <- fmap lines getContents let answer = solve [] $ (next.from) input putStrLn $ unlines $ map unlines $ take 10 answer solve :: [Position] -> [State] -> [Board] solve _ [] = mzero solve vs ((p@(d,c),b):queue) | on 'G' = return b `mplus` solve vs queue | on ' ' && null eq = solve (p:vs) (queue ++ (next.modify) (p,b)) | on ' ' && (fst.head) eq <= d = solve (p:neq) (queue ++ (next.modify) (p,b)) | otherwise = solve vs queue where on = (== b!!snd c!!fst c) (eq,neq) = partition ((== c).snd) vs next :: State -> [State] next ((d,(x,y)),b) = zip ns (repeat b) where ns = [(d+1,p) | p <- [(x,y-1),(x,y+1),(x-1,y),(x+1,y)]] from :: Board -> State from input = (startOf input, input) startOf :: Board -> Position startOf input = head [(0,(x,y)) | (y,cs) <- zip [0..] input, (x,c) <- zip [0..] cs, c=='S'] modify :: State -> State modify ((d,c@(x,y)),b) = ((d,c), putAt y (putAt x '$' (b!!y)) b) where putAt n v vs = take n vs ++ v : drop (n+1) vs
solve 第一引数の既訪リストを、盤上の現在位置を含むもの (eq) と含まないもの (neq) で分割。 eq が空なら探索を継続、 eq が空でなくて既訪の探索深さが現在位置に至るまでの探索深さと同じか小さい (小さくなることはないはず。未確認) 場合もやはり探索を継続。一方現在位置に至るまでの探索深さが既訪のものより大きくなる場合、最短経路にはなりえないのでこの探索を放棄。
とまあ、こういった考えをごくごく素直に表現したつもり。しかしやっぱりあっさりとは帰ってこないね…。