【问题标题】:Find a path through a maze in C++ recursion error在 C++ 递归错误中找到穿过迷宫的路径
【发布时间】:2018-01-28 21:22:04
【问题描述】:

我正在尝试编写一个通过迷宫找到路径的函数。还有另一个函数从文本文件中读取迷宫。目前,当迷宫为 20 行和 20 列时,我编写的用于查找路径的函数可以正常工作,但它不适用于任何其他变体。这是我为该函数编写的代码:

void find_paths(maze m, int r, int c, int rows, int cols) {
  if (r == rows - 1)
    display(m, rows, cols);
  else {
    if (r > 0 && m[r - 1][c] == space) // UP
    {
      m[r - 1][c] = path;
      find_paths(m, r - 1, c, rows, cols);
      m[r - 1][c] = space;
    }
    if (m[r + 1][c] == space) // DOWN
    {
      m[r + 1][c] = path;
      find_paths(m, r + 1, c, rows, cols);
      m[r + 1][c] = space;
    }
    if (m[r][c - 1] == space) // LEFT
    {
      m[r][c - 1] = path;
      find_paths(m, r, c - 1, rows, cols);
      m[r][c - 1] = space;
    }
    if (m[r][c + 1] == space) // RIGHT
    {
      m[r][c + 1] = path;
      find_paths(m, r, c + 1, rows, cols);
      m[r][c + 1] = space;
    }
  }
}

空格是一个字符 =' ' 路径是一个 char ='.'

这是程序读取的迷宫文件的截图。

这是程序执行的截图。

我是 C++ 新手,希望你能帮助我。

【问题讨论】:

  • 它解决了其他迷宫,但它一直打印它们至少8次或一直打印它们并且程序没有结束。
  • 你的算法有一个概念问题,因为它永远不会结束,找到很多很多的解决方案,直到无穷大。而且我认为你应该调试你的程序,你会发现是哪一行导致了问题。
  • 整理一个简短的完整示例,并将您遇到问题的迷宫作为文本包含在您的问题中。否则只是猜测。您最好使用调试器并弄清楚为什么您的递归永远不会结束。我没有看到明确的路径,也许你想要展示后返回。
  • 查找“深度优先搜索”和“广度优先搜索”。或洪水填充,因为这就是您在这里所做的。基本上,您需要检测您何时已经到过那里。
  • 迷宫是如何声明的?它应该知道它的行和列,使它们变得多余。看起来您在每次递归时都在制作整个迷宫的副本。

标签: c++ recursion maze


【解决方案1】:

没有太大的错误(尽管它可以更有效地完成)。很可能它不起作用,因为您缺少列的边界检查。 由于您允许列获得任何值,因此您可能超出了迷宫的范围。 您的另一个问题是,当您找到解决方案时,您仍然需要采用所有其他递归路径。

这只是对您的代码的一个小改动,应该可以工作:

bool done = false;

void find_paths(maze m, int r, int c, int rows, int cols) {
  if(done) {
      return;
  }
  if (r == rows - 1) {
    display(m, rows, cols);
    done = true;
  } else {
    if (r > 0 && m[r - 1][c] == space) // UP
    {
      m[r - 1][c] = path;
      find_paths(m, r - 1, c, rows, cols);
      m[r - 1][c] = space;
    }
    if (m[r + 1][c] == space) // DOWN
    {
      m[r + 1][c] = path;
      find_paths(m, r + 1, c, rows, cols);
      m[r + 1][c] = space;
    }
    if (c > 0 && m[r][c - 1] == space) // LEFT
    {
      m[r][c - 1] = path;
      find_paths(m, r, c - 1, rows, cols);
      m[r][c - 1] = space;
    }
    if (c < cols && m[r][c + 1] == space) // RIGHT
    {
      m[r][c + 1] = path;
      find_paths(m, r, c + 1, rows, cols);
      m[r][c + 1] = space;
    }
  }
}

【讨论】:

    【解决方案2】:

    正如 Benjamin Barrois 的评论中所提到的,您需要一种方法来知道您检查了一条路线,如果是,则不要再次使用它。

    我会建议使用另一个字符而不是 '.' (路径)将死胡同与实际解决方案区分开来,尽管这还不够。

    所以我会添加一个名为 visited = 'x'; 的变量并在返回时使用它。

    此外,您在第一个测试 (UP) 中检查了 r &gt; 0,但在另一个 if() (DOWN, LEFT, RIGHT) 中没有检查任何此类限制。虽然如果你在那里有正确的字符,它会起作用(即它会先撞墙),但如果不是这样,你就会开始打错字符。

    void find_paths(maze m, int r, int c, int rows, int cols) {
      if (r == rows - 1)
        display(m, rows, cols);
      else {
        if (r > 0 && m[r - 1][c] == space) // UP
        {
          m[r - 1][c] = path;
          find_paths(m, r - 1, c, rows, cols);
          m[r - 1][c] = visited;
        }
        if (r + 1 < rows && m[r + 1][c] == space) // DOWN
        {
          m[r + 1][c] = path;
          find_paths(m, r + 1, c, rows, cols);
          m[r + 1][c] = visited;
        }
        if (c > 0 && m[r][c - 1] == space) // LEFT
        {
          m[r][c - 1] = path;
          find_paths(m, r, c - 1, rows, cols);
          m[r][c - 1] = visited;
        }
        if (c + 1 < cols && m[r][c + 1] == space) // RIGHT
        {
          m[r][c + 1] = path;
          find_paths(m, r, c + 1, rows, cols);
          m[r][c + 1] = visited;
        }
      }
    }
    

    话虽如此,您当前的算法在找到解决方案时不会停止,因为它是递归的,它将永远持续下去。如果您希望能够退出,您的函数需要返回 true(成功!)或 false(继续搜索)。

    虽然使用递归机制的想法对于找到所有解决方案非常有用,尤其是(如果您要计算它)解决方案的长度,因此您只返回较短的解决方案(这通常是迷宫搜索的内容)约。)

    bool find_paths(maze m, int r, int c, int rows, int cols) {
      if (r == rows - 1) {
        display(m, rows, cols);
        return true;
      }
      else {
        if (r > 0 && m[r - 1][c] == space) // UP
        {
          m[r - 1][c] = path;
          if(find_paths(m, r - 1, c, rows, cols)) {
            return true;
          }
          m[r - 1][c] = visited;
        }
        if (r + 1 < rows && m[r + 1][c] == space) // DOWN
        {
          m[r + 1][c] = path;
          if(find_paths(m, r + 1, c, rows, cols) {
            return true;
          }
          m[r + 1][c] = visited;
        }
        if (c > 0 && m[r][c - 1] == space) // LEFT
        {
          m[r][c - 1] = path;
          if(find_paths(m, r, c - 1, rows, cols) {
            return true;
          }
          m[r][c - 1] = visited;
        }
        if (c + 1 < cols && m[r][c + 1] == space) // RIGHT
        {
          m[r][c + 1] = path;
          if(find_paths(m, r, c + 1, rows, cols) {
            return true;
          }
          m[r][c + 1] = visited;
        }
      }
      return false;
    }
    

    附带说明,这不是 C++ 特有的。

    【讨论】:

    • 你不知道迷宫是怎么定义的。这很可能是一个本地副本(在每次递归调用中),在这种情况下,修改它并不能满足您的要求。
    • 现在可以了,但是当我尝试不同的迷宫时它不起作用!
    • @MarwanElSharkawy 你是说我的改变有帮助还是没有帮助?当您说它不起作用时,您的意思是它根本没有找到解决方案,还是只是它不断地向您展示许多解决方案?
    • 另外,您没有向我们展示调用该find_paths() 函数的代码。您确定rowscols 参数设置正确吗?您是否每次都正确地将c 设置为入口点? r 呢?输入时总是设置为0吗?该信息可能会帮助我们找到您的问题。
    • 这不起作用,因为将单元格设置为“已访问”会影响所采用的所有递归路径。回溯时,迷宫必须恢复到之前的状态。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多