Google Code Jam の問題解決 ( 2009.1AA: "マルチベースの幸福" ) 厄介な (コード単位の) 解決策を思いついたので、それをどのように改善できるか興味があります。
簡単に言えば、問題の説明は次のとおりです。指定されたリストのすべての基数について、数字の二乗和を繰り返し計算すると 1 に達する、1 より大きい最小の数を見つけます。
elem
または擬似Haskellでの説明(無限リストに対して常に機能する場合に解決するコード):
solution =
head . (`filter` [2..]) .
all ((1 `elem`) . (`iterate` i) . sumSquareOfDigitsInBase)
そして私の厄介な解決策:
- ぎこちないというのは、この種のコードがあることを意味します。
happy <- lift . lift . lift $ isHappy Set.empty base cur
- isHappy 関数の結果をメモします。メモ化された結果マップに State モナドを使用する。
- 最初の解決策を見つけようとして、 (上記の疑似 Haskell のように)
head
and を使用しませんでした。これは、計算が純粋ではない (状態が変化する) ためです。filter
そのため、StateT をカウンターと共に使用して反復し、条件が満たされたときに計算を終了するために MaybeT を使用しました。 - すでに a の中にあり
MaybeT (StateT a (State b))
、条件が 1 つのベースに当てはまらない場合、他のベースをチェックする必要はないのでMaybeT
、スタックに別のベースがあります。
コード:
import Control.Monad.Maybe
import Control.Monad.State
import Data.Maybe
import qualified Data.Map as Map
import qualified Data.Set as Set
type IsHappyMemo = State (Map.Map (Integer, Integer) Bool)
isHappy :: Set.Set Integer -> Integer -> Integer -> IsHappyMemo Bool
isHappy _ _ 1 = return True
isHappy path base num = do
memo <- get
case Map.lookup (base, num) memo of
Just r -> return r
Nothing -> do
r <- calc
when (num < 1000) . modify $ Map.insert (base, num) r
return r
where
calc
| num `Set.member` path = return False
| otherwise = isHappy (Set.insert num path) base nxt
nxt =
sum . map ((^ (2::Int)) . (`mod` base)) .
takeWhile (not . (== 0)) . iterate (`div` base) $ num
solve1 :: [Integer] -> IsHappyMemo Integer
solve1 bases =
fmap snd .
(`runStateT` 2) .
runMaybeT .
forever $ do
(`when` mzero) . isJust =<<
runMaybeT (mapM_ f bases)
lift $ modify (+ 1)
where
f base = do
cur <- lift . lift $ get
happy <- lift . lift . lift $ isHappy Set.empty base cur
unless happy mzero
solve :: [String] -> String
solve =
concat .
(`evalState` Map.empty) .
mapM f .
zip [1 :: Integer ..]
where
f (idx, prob) = do
s <- solve1 . map read . words $ prob
return $ "Case #" ++ show idx ++ ": " ++ show s ++ "\n"
main :: IO ()
main =
getContents >>=
putStr . solve . tail . lines
Haskell を使用している他の参加者は、より優れた解決策を持っていましたが、問題の解決方法が異なりました。私の質問は、私のコードに対する小さな反復的な改善についてです。