解决问题,从谷歌码果酱(2009.1答:"多基幸福")我想出了一个尴尬的(代码-明智的)解决方案,并且我感兴趣的是它如何可以改进。

问题的说明中,不久:发现的最小数量大于1为其迭代计算的平方和个数字达到1,所有的基地从一个给定名单。

或说明伪Haskell(代码,就会解决如果 elem 总是可以作为无限的清单):

solution =
  head . (`filter` [2..]) .
  all ((1 `elem`) . (`iterate` i) . sumSquareOfDigitsInBase)

和我尴尬的解决方案:

  • 通过尴尬我是说它具有这样的代码: happy <- lift . lift . lift $ isHappy Set.empty base cur
  • 我memoize结果isHappy功能。使用国家单的memoized结果的地图。
  • 试图找到第一个解决方案,我没有用 headfilter (喜欢的伪haskell上述会),因为计算不是纯粹的(变化的状态)。所以我迭代使用StateT带一个计数器和一MaybeT终止计算的条件时举行。
  • 已经在里面了 MaybeT (StateT a (State b)), ,如果情况不保持一个基地,没有必要检查的其他人,所以我有另一个 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没有 好的解决方案, 但解决的问题不同。我的问题是关于小迭代的改善,我的代码。

有帮助吗?

解决方案

你的解决方案是肯定很尴尬在其使用(和性虐待)的元:

  • 通常是要建立一元零敲碎打叠的几个变压器
  • 这是不平常,但仍然发生时,堆叠的几个国家
  • 这是非常不寻常叠的几个可能的变压器
  • 它甚至更不寻常的使用MaybeT以中断一个循环

你的代码是有点太无意义:

(`when` mzero) . isJust =<<
   runMaybeT (mapM_ f bases)

而不是更容易阅读

let isHappy = isJust $ runMaybeT (mapM_ f bases)
when isHappy mzero

现在正把重点放在功能solve1,让我们简化它。一个简单的方法来这样做,是消除内MaybeT单.而不是一个永远的环打破当一个快乐的数被发现,你可以去周围的其他方法和recurse只有如果 数量并不高兴。

而且,你并不真正需要的国家单,你呢?人们总是可以替换的国家有一个明确的参数。

运用这些想法solve1现在看起来要好得多:

solve1 :: [Integer] -> IsHappyMemo Integer
solve1 bases = go 2 where
  go i = do happyBases <- mapM (\b -> isHappy Set.empty b i) bases
            if and happyBases
              then return i
              else go (i+1)

我会更汉满意这个代码。其余的解决方案是好的。一件事困扰着我是你扔掉的备忘录,缓对每个子问题.还有一个原因是什么?

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"

不你的解决方案会更有效,如果你再用它,而不是?

solve :: [String] -> String
solve cases = (`evalState` Map.empty) $ do
   solutions <- mapM f (zip [1 :: Integer ..] cases)
   return (unlines solutions)
  where
    f (idx, prob) = do
      s <- solve1 . map read . words $ prob
      return $ "Case #" ++ show idx ++ ": " ++ show s

其他提示

该单*类存在删除需要反复提升。如果你改变你的签名这样的:

type IsHappyMemo = Map.Map (Integer, Integer) Bool

isHappy :: MonadState IsHappyMemo m => Set.Set Integer -> Integer -> Integer -> m Bool

这样,你可以除去大的提升。然而,最长的序列的电梯不能删除,因为它是一个国家单内StateT,因此使用MonadState型类会给你的外StateT,在你需要tot得到内心状态。你可以把你的国家单在新和做MonadHappy级,类似于现有的单课程。

ListT (从 列表 包)没有一个更好的工作比 MaybeT 在停止计算,必要时。

solve1 :: [Integer] -> IsHappyMemo Integer
solve1 bases = do
  Cons result _ <- runList . filterL cond $ fromList [2..]
  return result
  where
    cond num = andL . mapL (isHappy Set.empty num) $ fromList bases

一些阐述在这怎么工作:

我们使用一个常规列表代码会有这样的:

solve1 bases = do
  result:_ <- filterM cond [2..]
  return result
  where
    cond num = fmap and . mapM (isHappy Set.empty num) bases

这个计算是发生在一个 State 单,但如果我们想获得生成的状态,我们就会有一个问题,因为 filterM 运行一元谓它变得对每一个元素 [2..], ,一个无限的清单。

有的单子列表, filterL cond (fromList [2..]) 代表一个名单,我们就可以访问的一个项目的时间作为一个单子的行动,使我们的元谓 cond 不是实际执行(并影响国家)除非我们消费的相应清单的项目。

类似地,实施 cond 使用 andL 让我们不计算和更新国家如果我们已经有了一个 False 结果从一个的 isHappy Set.empty num 计算。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top