当前位置: 首页 > 知识库问答 >
问题:

递归使用列表-Haskell

诸葛砚文
2023-03-14

我试图编写一个递归函数,它将包含整数列表的列表作为输入,并返回类型为([Int],Int]的元组。([Int],Int)

这是为“棋盘游戏”提供的,其中提供了一个棋盘:

 [[5,4,3,8,6],
  [0,2,1,0,7],
  [0,1,9,4,3],
  [2,3,4,0,9]]

这将是一个4行5列的电路板。列表中的数字是“硬币价值”。这个棋盘游戏的目标是从列表的顶部到底部收集硬币。你可以从最上面一排的任何位置开始,然后向下移动,你可以直接向下移动,也可以对角向左或向右移动。你需要的路径将为你提供最大的总硬币价值。

我创建了第一个函数,在其中输入一个路径列表[([Int],Int]),它返回具有最大硬币值的路径([Int],Int)。

现在我需要创建一个函数来实际生成我将输入到第一个函数中的路径列表。

我知道我将不得不使用递归。我将输入板(像上面的一个)和一个开始列。我必须取列号,然后创建所有可能路径的列表。如果我从列号开始,我接下来可能的步骤是位置(在下一行中)-相同的列号,列num-1和列num 1。我需要递归地调用它,直到我到达底部。

我如何能够存储这些路径步骤,然后存储所有可能的路径的最终列表?

([Int],Int)-[Int]是列表/列编号或行中的位置,Int是硬币价值。

我是haskell的新手,虽然我知道我必须做什么,但写代码真的很难。

共有3个答案

葛念
2023-03-14

如果您对使用我的软件包网格(userguide)感兴趣,请在此作为示例开始。(如果你不想使用它,你可能会发现一些源代码很有用。)

创建一个4行5列的网格。

λ> :m + Math.Geometry.Grid
λ> let g = rectSquareGrid 4 5
λ> indices g
[(0,0),(0,1),(0,2),(0,3),(1,0),(1,1),(1,2),(1,3),(2,0),(2,1),(2,2),(2,3),(3,0),(3,1),(3,2),(3,3),(4,0),(4,1),(4,2),(4,3)]

我们希望能够将“硬币值”映射到网格位置,所以我们将创建一个GridMap。

λ> :m + Math.Geometry.GridMap
λ> let m = lazyGridMap g [5,4,3,8,6,0,2,1,0,7,0,1,9,4,3,2,3,4,0,9]
λ> m
lazyGridMap (rectSquareGrid 4 5) [5,4,3,8,6,0,2,1,0,7,0,1,9,4,3,2,3,4,0,9]
λ> toList m
[((0,0),5),((0,1),4),((0,2),3),((0,3),8),((1,0),6),((1,1),0),((1,2),2),((1,3),1),((2,0),0),((2,1),7),((2,2),0),((2,3),1),((3,0),9),((3,1),4),((3,2),3),((3,3),2),((4,0),3),((4,1),4),((4,2),0),((4,3),9)]

我们可以找到网格中任何单元的邻居,但对于您的应用程序,我们遇到了一个小问题:我的RectSquareGrid类型不允许对角移动。

λ> neighbours (1,2) m
[(0,2),(1,3),(2,2),(1,1)]

现在,我很乐意创建一种新型的网格,满足您的需求。或者,您可以编写自己的函数,其中包括对角邻域:

λ> let neighbours2 (x, y) g = filter (`inGrid` g) [(x-1,y-1), (x-1,y), (x-1,y+1), (x,y-1), (x,y+1), (x+1,y-1), (x+1,y), (x+1,y+1)]
λ> neighbours2 (1,2) m
[(0,1),(0,2),(0,3),(1,1),(1,3),(2,1),(2,2),(2,3)]

但你只对允许向下移动感兴趣,无论是直线向下还是对角线向下,所以这里有一个更有用的函数:

λ> let allowedMoves (x, y) g = filter (`inGrid` g) [(x+1,y-1), (x+1,y), (x+1,y+1)]
λ> allowedMoves (1,2) m
[(2,1),(2,2),(2,3)]

现在我们可以编写一个函数,给出从给定索引到网格底部行的所有可能路径。

allPathsFrom a g | fst a == fst (size g) = [[a]]
                 | otherwise             = Prelude.map (a:) xs
  where xs = concatMap (\x -> allPathsFrom x g) ys
        ys = allowedMoves a g

例如:

λ> allPathsFrom (0,1) m
[[(0,1),(1,0),(2,0),(3,0),(4,0)],[(0,1),(1,0),(2,0),(3,0),(4,1)],[(0,1),(1,0),(2,0),(3,1),(4,0)],[(0,1),(1,0),(2,0),(3,1),(4,1)],[(0,1),(1,0),(2,0),(3,1),(4,2)],[(0,1),(1,0),(2,1),(3,0),(4,0)],[(0,1),(1,0),(2,1),(3,0),(4,1)],[(0,1),(1,0),(2,1),(3,1),(4,0)],[(0,1),(1,0),(2,1),(3,1),(4,1)],[(0,1),(1,0),(2,1),(3,1),(4,2)],[(0,1),(1,0),(2,1),(3,2),(4,1)],[(0,1),(1,0),(2,1),(3,2),(4,2)],[(0,1),(1,0),(2,1),(3,2),(4,3)],[(0,1),(1,1),(2,0),(3,0),(4,0)],[(0,1),(1,1),(2,0),(3,0),(4,1)],[(0,1),(1,1),(2,0),(3,1),(4,0)],[(0,1),(1,1),(2,0),(3,1),(4,1)],[(0,1),(1,1),(2,0),(3,1),(4,2)],[(0,1),(1,1),(2,1),(3,0),(4,0)],[(0,1),(1,1),(2,1),(3,0),(4,1)],[(0,1),(1,1),(2,1),(3,1),(4,0)],[(0,1),(1,1),(2,1),(3,1),(4,1)],[(0,1),(1,1),(2,1),(3,1),(4,2)],[(0,1),(1,1),(2,1),(3,2),(4,1)],[(0,1),(1,1),(2,1),(3,2),(4,2)],[(0,1),(1,1),(2,1),(3,2),(4,3)],[(0,1),(1,1),(2,2),(3,1),(4,0)],[(0,1),(1,1),(2,2),(3,1),(4,1)],[(0,1),(1,1),(2,2),(3,1),(4,2)],[(0,1),(1,1),(2,2),(3,2),(4,1)],[(0,1),(1,1),(2,2),(3,2),(4,2)],[(0,1),(1,1),(2,2),(3,2),(4,3)],[(0,1),(1,1),(2,2),(3,3),(4,2)],[(0,1),(1,1),(2,2),(3,3),(4,3)],[(0,1),(1,2),(2,1),(3,0),(4,0)],[(0,1),(1,2),(2,1),(3,0),(4,1)],[(0,1),(1,2),(2,1),(3,1),(4,0)],[(0,1),(1,2),(2,1),(3,1),(4,1)],[(0,1),(1,2),(2,1),(3,1),(4,2)],[(0,1),(1,2),(2,1),(3,2),(4,1)],[(0,1),(1,2),(2,1),(3,2),(4,2)],[(0,1),(1,2),(2,1),(3,2),(4,3)],[(0,1),(1,2),(2,2),(3,1),(4,0)],[(0,1),(1,2),(2,2),(3,1),(4,1)],[(0,1),(1,2),(2,2),(3,1),(4,2)],[(0,1),(1,2),(2,2),(3,2),(4,1)],[(0,1),(1,2),(2,2),(3,2),(4,2)],[(0,1),(1,2),(2,2),(3,2),(4,3)],[(0,1),(1,2),(2,2),(3,3),(4,2)],[(0,1),(1,2),(2,2),(3,3),(4,3)],[(0,1),(1,2),(2,3),(3,2),(4,1)],[(0,1),(1,2),(2,3),(3,2),(4,2)],[(0,1),(1,2),(2,3),(3,2),(4,3)],[(0,1),(1,2),(2,3),(3,3),(4,2)],[(0,1),(1,2),(2,3),(3,3),(4,3)]]

请注意,由于GridMap也是Grid,我们可以在m或g上调用上述所有函数

λ> allPathsFrom (0,1) m

如果你想让我在我的网格包中添加一个允许对角线移动的网格,请告诉我(nualeargais dot ie的艾米)。

佘飞鸣
2023-03-14

我想我现在可以(很容易地)把我对另一个问题的回答改编成这个问题。我列出了允许的索引组合,并将板映射到它们。(pat的评论帮助我提高了index_combinations)

*主要的

import Data.List
import Data.Ord
import Data.Maybe

r = [[5,4,3,8,6],
     [0,2,1,0,7],
     [0,1,9,4,3],
     [2,3,4,0,9]]

r1 = r !! 0
r2 = r !! 1
r3 = r !! 2
r4 = r !! 3

index_combinations = 
  [[a,b,c,d] | a <- [0..4], b <- [max 0 (a-1)..min 4 (a+1)], 
   c <- [max 0 (b-1)..min 4 (b+1)], d <- [max 0 (c-1)..min 4 (c+1)]]  

mapR xs = [r1 !! (xs !! 0), r2 !! (xs !! 1), 
           r3 !! (xs !! 2), r4 !! (xs !! 3)]

r_combinations = map mapR index_combinations
r_combinations_summed = zip r_combinations $ map (foldr (+) 0) r_combinations

result = maximumBy (comparing snd) r_combinations_summed
path = index_combinations !! fromJust (elemIndex result r_combinations_summed)
郑翰海
2023-03-14

在惯用的函数代码中,您不会在某些变量中“存储”中间值。而是将它们作为一个累积参数,使用foldr之类的函数传递。

http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:foldr

 类似资料:
  • 我试图使用递归打印链表中每个节点中的数据,但是我得到了越界错误,所以我认为递归函数有问题。 这是头文件: 基本上,我从公共函数调用私有助手函数。下面是两个函数的代码: 我认为问题出在if块中,因为如果没有下一个节点,我需要停止,但在返回之前还需要打印当前节点中的数据,但因为我已经调用了

  • 我有内部节点和终端节点的树状结构: 我现在有一个

  • 我正在寻找帮助,我正在尝试迭代具有订单()的产品,该产品还包含

  • 问题内容: 使用MySQL,我想从具有此类字段结构的表中返回父母列表。ID,PARENTID,NAME(标准的父子层次结构)。我想遍历树以返回所有“父母”的列表。 我意识到“嵌套集”可能是处理此问题的更好方法-但目前我无法更改数据的结构。我将来会希望这样做。当前-我的数据集实际上将包含一些深度级别- 没什么疯狂的……也许2-5,所以我的递归命中不应太“昂贵”。 我已经看过SQL Server获取父

  • 我的数据结构如下所示: Foo的每个实例都可以包含任意数量的S,这当然反过来又可以包含更多的S等等。那么,我该如何让FreeMarker通过这样的列表呢?

  • 还缺少的是将最后一个节点的next赋值为NULL。 在任何世界里,像这样的东西会起作用吗?它给出了一个运行时/分段错误。