Haskell中多参数函数中单个参数的记忆
我正在解决问题,并且我的当前解决方案超过了时间限制。我相信解决我问题的办法是记忆。但是,我不了解记录的备忘录解决方案 这是我当前解决方案中的主要功能Haskell中多参数函数中单个参数的记忆,haskell,recursion,Haskell,Recursion,我正在解决问题,并且我的当前解决方案超过了时间限制。我相信解决我问题的办法是记忆。但是,我不了解记录的备忘录解决方案 这是我当前解决方案中的主要功能 maxCuts :: Int -> Int -> Int -> Int -> Int maxCuts n a b c | n == 0 = 0 | n < 0 = -10000 | otherwise = max (max amax bmax) cmax where
maxCuts :: Int -> Int -> Int -> Int -> Int
maxCuts n a b c
| n == 0 = 0
| n < 0 = -10000
| otherwise = max (max amax bmax) cmax
where
amax = 1 + maxCuts (n - a) a b c
bmax = 1 + maxCuts (n - b) a b c
cmax = 1 + maxCuts (n - c) a b c
maxCuts::Int->Int->Int->Int->Int
maxCuts n a b c
|n==0=0
|n<0=-10000
|否则=max(max amax bmax)cmax
哪里
amax=1+maxCuts(n-a)a b c
bmax=1+maxCuts(n-b)a b c
cmax=1+maxCuts(n-c)a b c
如果a b和c相对于n较小,则此函数运行时间过长。我只是复制他们用于阶乘函数的解决方案,但该函数只接受一个参数。我有四个参数,但我只想在第一个参数
n
上键入memorization。请注意,a
b
和c
在递归调用中不会更改 像这样重写函数定义:
maxCuts :: Int -> Int -> Int -> Int -> Int
maxCuts n a b c = maxCuts' n where
maxCuts' n
| n == 0 = 0
| n < 0 = -10000
| otherwise = max (max amax bmax) cmax
where
amax = 1 + maxCuts' (n - a)
bmax = 1 + maxCuts' (n - b)
cmax = 1 + maxCuts' (n - c)
maxCuts::Int->Int->Int->Int->Int
maxCuts n a b c=maxCuts'n其中
麦克斯库茨酒店
|n==0=0
|n<0=-10000
|否则=max(max amax bmax)cmax
哪里
amax=1+maxCuts'(n-a)
bmax=1+maxCuts'(n-b)
cmax=1+maxCuts'(n-c)
现在,您有了一个可以记忆的单参数函数。重写函数定义,如下所示:
maxCuts :: Int -> Int -> Int -> Int -> Int
maxCuts n a b c = maxCuts' n where
maxCuts' n
| n == 0 = 0
| n < 0 = -10000
| otherwise = max (max amax bmax) cmax
where
amax = 1 + maxCuts' (n - a)
bmax = 1 + maxCuts' (n - b)
cmax = 1 + maxCuts' (n - c)
maxCuts::Int->Int->Int->Int->Int
maxCuts n a b c=maxCuts'n其中
麦克斯库茨酒店
|n==0=0
|n<0=-10000
|否则=max(max amax bmax)cmax
哪里
amax=1+maxCuts'(n-a)
bmax=1+maxCuts'(n-b)
cmax=1+maxCuts'(n-c)
现在您有了一个可以记忆的单参数函数。旁白:您的算法不就是在计算类似于
divn(最小[a,b,c])的东西吗
正如您所指出的,参数a、b和c不会改变,因此首先重写函数,将参数n
放在末尾
如果您决定使用列表来记忆所需的函数值
稍微注意确保GHC将保存映射列表:
import Debug.Trace
maxCuts' :: Int -> Int -> Int -> Int -> Int
maxCuts' a b c n = memoized_go n
where
memoized_go n
| n < 0 = -10000
| otherwise = mapped_list !! n
mapped_list = map go [0..]
go n | trace msg False = undefined
where msg = "go called for " ++ show n
go 0 = 0
go n = maximum [amax, bmax, cmax]
where
amax = 1 + memoized_go (n-a)
bmax = 1 + memoized_go (n-b)
cmax = 1 + memoized_go (n-c)
test1 = print $ maxCuts' 1 2 3 10
运行test2
显示对n
的相同值调用了多次go
更新
为了避免创建大型未评估的Thunk,我将使用BangPatterns
对于amax
、bmax
和cmax
:
{-# LANGUAGE BangPatterns #-}
maxCuts' ... =
...
where
!amax = 1 + ...
!bmax = 1 + ...
!cmax = 1 + ...
旁白:你的算法不就是在计算类似于divn(最小[a,b,c])的东西吗
正如您所指出的,参数a、b和c不会改变,因此首先重写函数,将参数n
放在末尾
如果您决定使用列表来记忆所需的函数值
稍微注意确保GHC将保存映射列表:
import Debug.Trace
maxCuts' :: Int -> Int -> Int -> Int -> Int
maxCuts' a b c n = memoized_go n
where
memoized_go n
| n < 0 = -10000
| otherwise = mapped_list !! n
mapped_list = map go [0..]
go n | trace msg False = undefined
where msg = "go called for " ++ show n
go 0 = 0
go n = maximum [amax, bmax, cmax]
where
amax = 1 + memoized_go (n-a)
bmax = 1 + memoized_go (n-b)
cmax = 1 + memoized_go (n-c)
test1 = print $ maxCuts' 1 2 3 10
运行test2
显示对n
的相同值调用了多次go
更新
为了避免创建大型未评估的Thunk,我将使用BangPatterns
对于amax
、bmax
和cmax
:
{-# LANGUAGE BangPatterns #-}
maxCuts' ... =
...
where
!amax = 1 + ...
!bmax = 1 + ...
!cmax = 1 + ...
最简单的方法就是取消函数的rry,所以实际上只有一个参数:maxCuts::(Int,Int,Int,Int)->Int
最简单的方法就是取消函数的rry,所以实际上只有一个参数:maxCuts::(Int,Int,Int,Int)->Int