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

为什么我的递归寻路算法行为不正确?

东方方伟
2023-03-14

对于一个项目,我已经程序化地生成了一系列坐标为(0,0)-->的“瓦片”; (x,y)其中(x,y)是平铺数组的最大宽度和高度。 然后用方块随机填充这个平铺数组,并给出一个入口和多个出口点。 我正在尝试创建一个算法,在给定一个起点的情况下,检查是否可以到达所有的出口点。 为此,每个瓦片包含关于其N-E-S-W相邻瓦片的数据,并且调用一个递归函数,该函数检查当前瓦片的出口,然后移动到北瓦片,然后对东,西,然后对南进行同样的操作。

下面是代码的一个(伪)示例,除了不检查出口,而是访问所有可用的瓦片并对它们进行计数(或者应该这样做):

public class Algo
{
    public int Count(Tile tile)
    {
        tile.Visited = true;
        foreach (direction in NESW)
        {
            if(!tile.direction.IsPopulated & !tile.direction.Visited)
            {
                 return Count(tile.direction) + 1;
            }
        }
        return 0;
     }
}

IsPopulated是一个布尔值,如果平铺中填充了一个正方形,则返回true;Visited是一个布尔值,如果平铺已被访问,则返回true。 在瓦片空间周围有一个方块周长,它确保算法保持在瓦片空间的边界内

对于像这样的平铺布局:

箭头指示算法的起始点,方向和结束点(较暗的位是填充的平铺)

算法返回17而不是预期的21。

看起来,当算法到达一个不能在任何方向移动的块时,函数返回计数,而不是返回调用堆栈并重试。

我尝试过的另一个版本如预期的那样工作,然而,它没有结果,并且在方法之外变异了类的一个成员变量。

public class Algo2
{
    count = 0;
    public void Count(Tile tile)
    {
        tile.Visited = true;
        count += 1;
        foreach (direction in NESW)
        {
            if(!tile.direction.IsPopulated & !tile.direction.Visited)
            {
                 return Count(tile.direction);
            }
        }
     }
}

这将返回值21,并按预期工作。

为什么有副作用的非成果递归函数能工作,而没有副作用的成果函数却不工作?

共有1个答案

怀洛华
2023-03-14

寻找路径需要回溯。 即,您试图找到一条路径。 如果你到达目标,你就停下来。 如果到达死胡同或已经访问过的路径,则清除访问过的标志并返回,即将控件放回嵌套较少的递归级别。 这个级别然后尝试其他方向。

像这样的东西:

bool FindPath(Tile tile)
{
    tile.Visited = true;
    if (tile.IsTarget)
    {
        return true;
    }
    foreach (direction in NESW)
    {
        var nextTile = tile.direction;
        if(!nextTile.IsPopulated && !nextTile.Visited && FindPath(nextTile))
             return true;
        }        
    }
    // Back tracking
    tile.Visited = false;
    return false;
}

如果对findPath的初始调用返回true,则目标的路径将用visited=true块标记。

另一个选择是找到所有可能的路径到目标(或到几个目标)。 为此,您需要输出当前找到的路径,然后继续。

List<Tile> _path = new List<Tile>();

void FindAllPaths(Tile tile)
{
    tile.Visited = true;
    _path.Add(tile);
    if (tile.IsTarget)
    {
        OutputPath(_path);
        return; // If you want to go past a target to
                // find other targets, remove this `return`.
    }
    foreach (direction in NESW)
    {
        var nextTile = tile.direction;
        if(!nextTile.IsPopulated && !nextTile.Visited)
        {
             FindPath(nextTile);
        }        
    }
    // Back tracking
    tile.Visited = false;
    _path.Remove(tile);
}

不是在outputPath方法中使用带有路径块的列表,您还可以循环遍历所有块并检查visited标志。 对于大型迷宫,使用列表可能更有效。

这两种算法并不是针对所有未填充的瓦片进行计数。 但您可以计算路径平铺,从而得到路径长度。 如果您使用列表,这是列表计数,否则您也会回溯计数。 即tile.visited=true; count++;tile.visited=false; 末尾的count--;

 类似资料:
  • 我有一个(co?)递归函数对,它们处理元组列表,并根据一些开始和结束条件将它们折叠成批处理。 我做得不多,所以我可能很愚蠢。 我已经修改了一个简单的非尾部递归版本,通过明确引入一个“tot”参数来构成当前折叠状态,我认为这是尾部递归的,但我在大输入上得到了可怕的堆栈溢出。。。。(在调试器和(调试)中)。exe) 作为一个明确的折叠,可能有更好的方法来做到这一点...但这几乎不是重点,重点是为什么它

  • 问题内容: 我有一个自称的函数: 现在,如果我只输入,则一切正常: 但是,如果我输入其他内容,然后输入 ,则会得到以下信息: 我不知道为什么要回来,因为它应该只回来。这None是哪里来的,我该如何修复我的功能? 问题答案: 之所以返回,是None因为当你递归调用它时: ..你不返回该值。 因此,当确实发生递归时,返回值将被丢弃,然后你就无法使用该函数了。退出函数的末尾意味着隐式返回None,就像这

  • 主要内容:src/runoob/graph/Path.java 文件代码:图的寻路算法也可以通过深度优先遍历 dfs 实现,寻找图 graph 从起始 s 点到其他点的路径,在上一小节的实现类中添加全局变量 from数组记录路径,from[i] 表示查找的路径上i的上一个节点。 首先构造函数初始化寻路算法的初始条件,from = new int[G.V()] 和 from = new int[G.V()],并在循环中设置默认值,visited 数组全部为false,fr

  • 我编写了以下代码来实现BST的递归插入方法。但是当我以遍历顺序打印树时,它会在插入之前打印原始树。似乎没有插入元素。请帮帮我。提前谢谢。另外,请建议更改代码。顺便说一下,初始树的遍历顺序是2 5 6 7 8。

  • 问题内容: 尝试编译时出现“不是语句”的编译错误,代码为: 当这些功能是: 有任何想法吗? 问题答案: 是的,您不能像这样使用条件运算符。其目的是计算一个或另一个 表达式 。它并不是要选择一个要执行的 语句 或另一条 语句 的方法。 只需使用:

  • 问题内容: 因此,我在闲逛时使用了递归,我发现使用递归的循环比常规的while循环要慢得多,我想知道是否有人知道为什么。我已经包括了我下面所做的测试: 但是,在上一次测试中,我注意到如果删除该语句,则表明速度略有提高,因此我想知道if语句是否是造成循环速度差异的原因? 问题答案: 您已将函数编写为尾递归。在许多命令式和函数式语言中,这将触发尾部递归消除,在这种情况下,编译器用简单的JUMP替换了C

  • 问题内容: 我正在遵循一个教程来尝试学习如何使用BeautifulSoup。我正在尝试从下载的HTML页面上的URL中删除名称。至此,我的工作非常顺利。 但是当我进入下一部分时 我得到这个错误 问题答案: 这是IDLE和BeautifulSoup对象(子类)之间的错误交互。见问题1757057;已经有一段时间了。 解决方法是先将对象转换为纯unicode值:

  • 我使用react和laravel开发了一个应用程序来显示酒店列表。当用户点击一个单一的酒店,我希望该酒店的细节显示在一种类型的‘单一’视图。然而,尽管在主列表视图中,我使用正确的路由模式链接到单个页面,并且我在路由器中定义了该模式,但当我单击该链接时,我会被带到一个“404 not found”页面。 编辑文章的编辑链接也是如此。 任何关于如何解决这个问题的想法都将非常感谢! 谢谢, 罗伯特·杨