Algorithm 树状结构中的递归

Algorithm 树状结构中的递归,algorithm,recursion,f#,tree,maze,Algorithm,Recursion,F#,Tree,Maze,作为一个学校项目,我必须使用回溯法递归地在迷宫中找到解决方案,在线性问题上,我通常没有递归的问题解决算法,但是当涉及到多个选择/路径时,我不知道如何只找到一个解 问题参数: 矩阵中表示的迷宫,有多种到达同一终点的方法 起点 使用的语言: F# 代码的输出: ████████████████████ █ █ ██ █ ███ ███ █████ █ ██ █ █ █ █ █ ██ █ █ █ █ █ █ █ ███ ██ █ █Sxxxx

作为一个学校项目,我必须使用回溯法递归地在迷宫中找到解决方案,在线性问题上,我通常没有递归的问题解决算法,但是当涉及到多个选择/路径时,我不知道如何只找到一个解

问题参数:

  • 矩阵中表示的迷宫,有多种到达同一终点的方法
  • 起点
使用的语言:

  • F#
代码的输出:

████████████████████
█     █           ██
█ ███ ███ █████ █ ██
█   █   █   █   █ ██
█ █ █ █ █ █ █ ███ ██
█     █Sxxxx  █   ██
█ █████ █ █x███ █ ██
█     █   █xxx█   ██
█ █ █ ███████x██████
█ █ █   █   █x    ██
█ █ ███ █ █ █x███ ██
█   █   █ █  x█   ██
█ ███ ███ █ █x█ █ ██
█            x█   ██
███ █████████x███ ██
███ █     █xxx█ █ ██
███ █ █ █ █x███ █ ██
███   █ █xxx█     ██
█████████x██████████
█████████E██████████
let rec dfs(x,y,path,visited) =
        let rec checkVisited point visited = 
            match visited with
            | [] -> false
            | (x,y)::xs -> if point = (x,y) then true else checkVisited point xs
        let adjacents = [(x,y+1);(x+1,y);(x,y-1);(x-1,y)]
        for point in adjacents do
            if point = this.endPoint then
                this.solutionPath <- path
            else
                if checkVisited point visited = false && this.checkPoint point && this.isWall point = false then
                    dfs(fst(point),snd(point),(path@[point]),(visited@[(x,y)]))
#:墙壁
 : 路径
E:终点
S:起点

代码部分:

████████████████████
█     █           ██
█ ███ ███ █████ █ ██
█   █   █   █   █ ██
█ █ █ █ █ █ █ ███ ██
█     █Sxxxx  █   ██
█ █████ █ █x███ █ ██
█     █   █xxx█   ██
█ █ █ ███████x██████
█ █ █   █   █x    ██
█ █ ███ █ █ █x███ ██
█   █   █ █  x█   ██
█ ███ ███ █ █x█ █ ██
█            x█   ██
███ █████████x███ ██
███ █     █xxx█ █ ██
███ █ █ █ █x███ █ ██
███   █ █xxx█     ██
█████████x██████████
█████████E██████████
let rec dfs(x,y,path,visited) =
        let rec checkVisited point visited = 
            match visited with
            | [] -> false
            | (x,y)::xs -> if point = (x,y) then true else checkVisited point xs
        let adjacents = [(x,y+1);(x+1,y);(x,y-1);(x-1,y)]
        for point in adjacents do
            if point = this.endPoint then
                this.solutionPath <- path
            else
                if checkVisited point visited = false && this.checkPoint point && this.isWall point = false then
                    dfs(fst(point),snd(point),(path@[point]),(visited@[(x,y)]))
让记录dfs(x、y、路径、已访问)=
let rec checkVisited point visited=
拜访
|[]->false
|(x,y)::xs->如果点=(x,y),则为true,否则检查到访点xs
设邻接项=[(x,y+1);(x+1,y);(x,y-1);(x-1,y)]
对于邻接中的点,请执行以下操作:
如果point=this.endPoint,则

this.solutionPath您当前的方法看起来基本上还可以。但是,由于您正在进行深度优先搜索,您面临的主要问题是,没有任何东西可以阻止您尝试无限长的路径,例如
[(1,1);(1,2);(1,1);…]
,而不是进入更高效的路径。为了避免这种情况,您可以扫描路径,查看建议的下一个点是否已经在路径中(这在列表长度上最多需要线性时间,对于小问题大小可能很好),或者将访问的点集作为额外参数传递给递归函数(这将允许更快的成员资格查询)

另一个问题是,您没有任何方法来组合您可以选择的不同分支的结果。一种简单的方法是将内部函数的返回类型更改为选项类型,并从顶部返回
Some(path)
(if
),然后将else重写为类似的类型

[x, y+1
 x, y-1
 x+1, y
 x-1, y]
|> List.tryPick (fun (x',y') -> if this.checkPoint(x',y') then 
                                    sol(x', y', (x,y)::path)
                                else None)
这是递归地依次尝试每个可能的方向,并返回第一个成功的方向。这不一定会返回最短路径,因为它是深度优先搜索。您还可以轻松创建一个变量,该变量返回所有可能路径的列表,而不是使用选项(最大的变化是使用
list.collect
而不是
list.tryPick
),在这种情况下,如果您愿意,您可以从列表中选择最短的解决方案,虽然这需要进行大量的中间计算


一个更复杂的变化是切换到广度优先搜索,而不是深度优先,这将让您非常容易地返回最短路径。从概念上讲,一种方法是跟踪所有“可见”点的最短路径(仅从
[s],[]]
开始,以及一组尚未探索其子项的点(再次从
[s]
开始)。然后,只要有需要探索的点,就收集所有不同的子项;对于每个还没有已知路径的子项,添加路径并将其放入下一组要探索的子项中。

基本上,您是在试图找到一个解决方案,该解决方案将为您提供到最终点的最短路径。因为有多条路径可供选择最后一点。假设你正在试图求解到e的最短路径。但是你在试图求解什么,比如你只是想找出任何一条通向e的特殊路径,或者你想找到所有可能到达e的路径。只是想理解。明白了,这很容易,我不精通F#,如果我提供逻辑,会有帮助吗?Wh我知道你会说其他语言吗?返回所有路径也是一种有很好证明的方法。首先研究解决迷宫;做出有效的尝试;如果你仍然失败,发布你的结果。你已经有了一个很好的开始。所以我尝试了DFS并更新了答案,现在的问题是它给了我Stackoverflow,可能是因为我如果我没有检查我是否已经在同一点上,正如你所建议的,我搜索了BFS,应该可以解决问题,但我只在迭代模式下找到它,我必须递归地解决问题,你能帮我吗?谢谢你的回复anyway@Stecco我的最后一段指出了如何递归地进行广度优先搜索t、 如果遇到问题,您可以尝试并发布更新。但我认为,修复深度优先搜索以检查点是否已出现在路径中会更容易,因为您已经获得了。我现在使用新代码更新了问题,检查点是否已出现,但返回时它不起作用解决方案只是给出了一个空的array@Stecco-您仍然存在我在第二段中提到的问题;您没有将调用的结果合并到
dfs
,您只是运行前三个,但忽略结果A并返回最后一个调用的结果。是的,但我真的不知道如何解决问题,我不是r对于树状结构上的递归逻辑,你能修改一下代码让我理解吗?我非常感激