回忆录及;Haskell中的Euler问题15项目

回忆录及;Haskell中的Euler问题15项目,haskell,memoization,Haskell,Memoization,我一直在学习Haskell,并在学习过程中解决Euler项目的问题。我并不是真的为欧拉问题的答案而烦恼(我很乐意使用蛮力,或者用其他语言),而是方法 我坚持在合理的时间内做第15题。它要求提供20x20网格从左上角到右下角的非回溯路由数 我想说,很明显,我们的想法是记忆(sp?)函数,但我不确定该怎么做。我在谷歌上搜索到了Haskell Cafe,我天真地尝试去适应它,但最终得到了: memRoute :: (Int,Int) -> Int memRoute (x,y) = fromJus

我一直在学习Haskell,并在学习过程中解决Euler项目的问题。我并不是真的为欧拉问题的答案而烦恼(我很乐意使用蛮力,或者用其他语言),而是方法

我坚持在合理的时间内做第15题。它要求提供20x20网格从左上角到右下角的非回溯路由数

我想说,很明显,我们的想法是记忆(sp?)函数,但我不确定该怎么做。我在谷歌上搜索到了Haskell Cafe,我天真地尝试去适应它,但最终得到了:

memRoute :: (Int,Int) -> Int
memRoute (x,y) = fromJust $ lookup (x,y) $ map (\t -> (t,route t)) [(x,y) | x <- [0..20], y <- [0..20]]

route (0,0) = 0
route (_,0) = 1
route (0,_) = 1
route (x,y) = memRoute (x-1,y) + memRoute (x,y-1)
memRoute::(Int,Int)->Int
memRoute(x,y)=fromJust$lookup(x,y)$map(\t->(t,route t))[(x,y)| x掷几点

memRoute::(Int,Int)->Int
memRoute(x,y)=跟踪(“mem:++显示(x,y))
来自公正$
查找(x,y)$
地图(\t->(t,路线t))
[(x,y)| x在我看来,“记忆化”被高估了。没有
一刀切的记忆技术(在任何编程中
语言)将每个案例计算转化为
一般计算。你必须理解每个问题,
并组织事情以控制所需的内存量
使用

在这种情况下,要获取
nxm
矩形的路径数, 您不需要记住所有较小矩形的总数, 只适用于两个方向都小一步的矩形。 所以你可以一行一行地积累,忘记所有的总数 随走随变小的矩形

在哈斯凯尔,懒惰是这种情况下的完美选择。它可以缓解压力 你需要做所有的工作来准确地记录要记住的东西 还有什么要忘记的呢?只需计算一个无限大的总网格就可以了 所有可能的矩形,让Haskell完成剩下的工作

对于零行,您只有底线。无论它有多长, 到终点只有一条路径,因此路径的数量是有限的
重复1

要从上一行计算网格中的一行,请从
1
(无论你有多高,只有一条直线向下), 然后,在每一步中,您都会在 上一行和当前行中的上一步。我们总共有:

iterate (scanl (+) 1 . tail) (repeat 1) !! 20 !! 20

这会在GHCi提示下立即为我计算答案。

发生的情况是,每次调用memRoute时都会重新计算您的备忘录表。虽然不是完整的(幸运的!),但至少一次调用中完成的工作不会与其他调用共享。我能想到的最简单的重写是:

memRoute = let table = map (\t -> (t,route t)) [(x,y) | x <- [0..20], y <- [0..20]]
           in  \(x,y) -> fromJust $ lookup (x,y) $ table

memRoute=let table=map(\t->(t,route t))[(x,y)| x我还没有读过你的程序,但我想让你知道有一个聪明的O(1)解决方案。更一般地说,这是一个枚举组合数学的问题。预期的解决方案实际上不是常数时间——算术不是免费的,特别是当涉及阶乘时——但它肯定比实际迭代每条路径要有效得多。这个问题很可怕……我仍然记得它……而且尝试老实说,当他们看到这个问题时,谁能想到帕斯卡的三角形:)虽然我很欣赏你的回答的优雅,(我当然没有想过这样做),我真的想用这个Euler问题作为一个工具,更好地掌握Haskell中的记忆,而不是解决问题本身。这正是我的观点。这是在Haskell中进行记忆的一种方法。当你创建一个惰性数据结构时,Haskell会自动记忆实际计算的部分,直到它们完成为止不再需要,然后它会垃圾收集它们。我要补充的是,如果我们正在寻找的是解决Project Euler问题的最佳解决方案,那么即使是这种更简单的备忘录也是错误的方法。不难证明
numPaths a b==comb(a+b)b
,其中,
comb
是组合数学中常用的组合函数。在实践中,考虑“记忆化”作为一种编程技术,在任何编程语言中都是一个坏主意。它会把你的注意力从手头的任务上移开。用你的大脑解决问题,让记忆的使用自然发生。@Bones先生:事实上,这正是人们通常所说的“记忆化”的意思在Haskell中:构建一个无限的惰性数据结构,其中包含每个可能的参数组合的结果,用数据结构本身的索引替换递归调用这只是一个具有一个非负整数参数的函数的特例。Yitz的算法对于这个问题的特定递归结构也是一个特例。我知道这是很久以前的事了,但你的帖子让人大开眼界。然而,对于像我这样的noob来说,这更像是一种巫术。你有没有机会详细说明你的答案一步一步地…我正在努力地跟随它:(。我会很高兴的!
import Data.Array

routes :: (Int,Int) -> Int
routes = (rte !)
  where rte = array ((1,1), (n,n))
                    [ ((x,y), route (x,y)) | x <- [1 .. n],
                                             y <- [1 .. n] ]
        route (1,1) = 0
        route (_,1) = 1
        route (1,_) = 1
        route (x,y) = rte ! (x-1,y) + rte ! (x,y-1)
        n = 20
iterate (scanl (+) 1 . tail) (repeat 1) !! 20 !! 20
memRoute = let table = map (\t -> (t,route t)) [(x,y) | x <- [0..20], y <- [0..20]]
           in  \(x,y) -> fromJust $ lookup (x,y) $ table