Haskell 项目15-最后一次尝试
在过去的三天里,我一直在努力解决哈斯克尔的问题 以下是我目前的状态:Haskell 项目15-最后一次尝试,haskell,Haskell,在过去的三天里,我一直在努力解决哈斯克尔的问题 以下是我目前的状态: import Data.Map as Map data Coord = Coord Int Int deriving (Show, Ord, Eq) corner :: Coord -> Bool corner (Coord x y) = (x == 0) && (y == 0) side :: Coord -> Bool side (Coord x y) = (x == 0) || (y
import Data.Map as Map
data Coord = Coord Int Int deriving (Show, Ord, Eq)
corner :: Coord -> Bool
corner (Coord x y) = (x == 0) && (y == 0)
side :: Coord -> Bool
side (Coord x y) = (x == 0) || (y == 0)
move_right :: Coord -> Coord
move_right (Coord x y) = Coord (x - 1) y
move_down :: Coord -> Coord
move_down (Coord x y) = Coord x (y - 1)
calculation :: Coord -> Integer
calculation coord
| corner coord = 0
| side coord = 1
| otherwise = (calculation (move_right coord)) + (calculation (move_down coord))
problem_15 :: Int -> Integer
problem_15 size =
calculation (Coord size size)
它工作得很好,但如果“n”变大,则速度非常慢
据我所知,我可以使用动态编程和哈希表(例如Data.Map)来缓存计算值
我试过,但没有成功。我试过了,但下一个错误比上一个更可怕。所以我请求您的帮助:如何缓存已计算的值
我知道这个问题的数学解(Pascal三角形),但我对算法解感兴趣。这个问题更适合二维数组缓存,因为输入值的范围是有界的
import Control.Applicative
import Data.Array
data Coord = Coord Int Int deriving (Show, Ord, Eq, Ix)
calculation :: Coord -> Integer
calculation coord@(Coord maxX maxY) = cache ! coord where
cache = listArray bounds $ map calculate coords
calculate coord
| corner coord = 0
| side coord = 1
| otherwise = cache ! move_right coord + cache ! move_down coord
zero = Coord 0 0
bounds = (zero, coord)
coords = Coord <$> [0..maxX] <*> [0..maxY]
导入控件。应用程序
导入数据。数组
数据坐标=坐标积分推导(显示、Ord、Eq、Ix)
计算::坐标->整数
计算坐标@(坐标maxX maxY)=缓存!坐标在哪里
cache=listArray边界$map计算坐标
计算坐标
|角坐标=0
|侧坐标=1
|否则=缓存!向右移动坐标+缓存!向下移动坐标
零=坐标0
边界=(零,坐标)
coords=Coord[0..maxX][0..maxY]
我们将派生Ix
添加到Coord中,以便直接将其用作数组索引,并且在计算中,我们使用Coord 0 0
的下限和Coord
的上限初始化二维数组cache
。然后,我们只引用缓存中的值,而不是递归调用calculation
现在,我们可以相对快速地计算出较大的值
*Main>问题15 1000
2048151626989489714335162502980825044396424887981397033820382637671748186202083755828932994182610206201464766319998023692415481798004524792018047549769261578563012896634320647148511523952516512277685886115395462561479073786684641544445336176137700738556738145896300713065104559595144798887462063687185145518285511731662762536637730846829322553890497438594814317550307837964443708100851637248274627914170166198837648408435414308177859470377465651884755146807496946749238030331018187232980096685674585602525499101181135253534658887941966653674904511306110096311906270342502293155911108976733963991149120
既然您已经知道正确(高效)的解决方案,我不会为您破坏任何东西:
您可以使用数组(这里非常合适,因为域是一个矩形)
然后用它来运行
evalState (calculation target) Map.empty
或者你可以用一个关于黑客的回忆录软件包,我记得这是我脑海中的一个,但是还有更多的,可能还有更好的。(当然还有更多可能的方法。)使用动态规划和简单数组。那样的话,复杂性就是二次的。谢谢。这个语法是什么意思:coord@(coord maxX maxY)@demas它是一个“as模式”,将整个值绑定到
coord
,并将部分(这里的坐标)绑定到括号中模式的适当部分。@shang:所需的结果不会在缓存中!零
?不是缓存!协调
始终0
?@gspr:不,相反<代码>缓存!零==计算(坐标0)==0@shang:哦,对了,我的错!我的(心理)索引与你的相反。这种数组解决方案存在深度递归问题,导致非常大的参数数出现堆栈溢出(当然不适用于原始的20
)。我曾经尝试过一个seq
s序列,其步长取决于实现。也许还有别的办法吗?
import qualified Data.Map as Map
import Control.Monad.State.Strict
type Path = State (Map Coord Integer)
calculation :: Coord -> Path Integer
calculation coord = do
mb_count <- gets (Map.lookup coord)
case mb_count of
Just count -> return count
Nothing
| corner coord -> modify (Map.insert coord 0) >> return 0 -- should be 1, IMO
| side coord -> modify (Map.insert coord 1) >> return 1
| otherwise -> do
above <- calculation (move_down coord)
left <- calculation (move_right coord)
let count = above + left
modify (Map.insert coord count)
return count
evalState (calculation target) Map.empty