【问题标题】:Flood Fill Algorithm - Maze Navigation洪水填充算法 - 迷宫导航
【发布时间】:2013-04-03 00:04:47
【问题描述】:

我正在尝试实现一个版本的洪水填充算法,以帮助解决微型鼠标迷宫的最短距离路径。它的工作方式与常规洪水填充相同,只是每个相邻的未填充位置都将分配一个数字,表示该位置到起始位置的距离。每次算法移动到不同的单元格时,数字都会增加一。这是一个从左下角开始的没有墙的迷宫示例。

2 3 4
1 2 3
0 1 2

这是我当前的代码...

void nav_flood_rec(struct nav_array *array, int row, int column, int flood_num)
{
    //Check the base case (not shown here)
    if (base_case)
        return;

    //Assign the flood number
    arrray->cells[row][column]->flood_number = flood_num;

    //North
    nav_flood_rec(array, row + 1, column, flood_num + 1);

    //East
    nav_flood_rec(array, row, column + 1, flood_num + 1);

    //South
    nav_flood_rec(array, row - 1, column, flood_num + 1);

    //West
    nav_flood_rec(array, row, column - 1, flood_num + 1);
}

我遇到的问题是递归不是一次一步进行(有点含糊,但让我解释一下)。而不是检查所有方向然后继续算法将继续向北移动而不检查其他方向。似乎我想让其他递归调用以某种方式产生,直到检查其他方向。有人有什么建议吗?

【问题讨论】:

    标签: c algorithm flood-fill


    【解决方案1】:

    当您描述的内容听起来像是您想要广度优先搜索时,您已经实现了类似于深度优先搜索的东西。

    使用队列而不是堆栈。您在这里没有显式使用堆栈,但递归本质上是一个隐式堆栈。队列也将解决堆栈溢出的问题,这似乎很可能与这么多的递归。

    此外,正如 G.Bach 所说,您需要将单元格标记为已访问,以便您的算法终止。

    【讨论】:

    • +1 这听起来很像 BFS。队列将解决堆栈溢出问题,但不会解决非终止循环。处理过的单元格需要这样标记。
    • 哦,我知道我哪里出错了。唯一的问题是这是在 mirco 处理器上,并且只有内存堆栈(没有动态内存),这意味着没有 malloc()。我可以使用数组来实现队列,但这似乎效率低下。
    • @StefanBossbaly 如果您知道队列最多可以容纳多少个元素,那么您可以非常有效地做到这一点。分配一个数组,保留一个front 和一个length 计数器,每次删除项目时递增front 计数器并递减length 计数器,每次将项目放入时递增length 计数器队列。做两个增量模数组的大小。 front 计数器告诉您下一个要处理的元素在哪里,length 计数器告诉您队列中有多少元素。关于堆栈溢出问题,您需要标记单元格。
    【解决方案2】:

    Wikipedia's article on the subject:

    下面的伪代码显示了一个明确的基于队列的实现。它类似于简单的递归解决方案,不同之处在于它不是进行递归调用,而是将节点推入 LIFO 队列——充当堆栈——以供消费:

     Flood-fill (node, target-color, replacement-color):
     1. Set Q to the empty queue.
     2. Add node to the end of Q.
     4. While Q is not empty: 
     5.     Set n equal to the last element of Q.
     7.     Remove last element from Q.
     8.     If the color of n is equal to target-color:
     9.         Set the color of n to replacement-color.
     10.        Add west node to end of Q.
     11.        Add east node to end of Q.
     12.        Add north node to end of Q.
     13.        Add south node to end of Q.
     14. Return.
    

    【讨论】:

      【解决方案3】:

      您调用north() 而不测试任何条件。因此,您的递归将按顺序:

      • 1) 基本情况测试
      • 2) 设置新的洪水编号
      • 3) 遇到//north,拨打nav_flood_rec()
      • 4) 重复。

      如您所见,您将永远无法接通其他电话。您需要实现测试条件、对其进行分支或类似的操作。

      不太确定您要做什么,但您可以将另一个结构作为参数传递,并为每个方向设置一个值,然后测试它们是否相等......就像......

      struct decision_maker {
        int north;
        int south;
        int west;
        int east;
      };
      

      然后在你的代码中:

      /* assume dm is passed as a pointer to a decision_maker struct */
      
      if (dm->north > dm->south) {
        if (dm->south > dm->east) {
          dm->east++; // increment first
          // call east
        } else if (dm->south > dm->west) {
          dm->west++; // increment first
          // call west
        } else {
          dm->south++;
          // call south
      } else {
          dm->north++;
          // call north
      }
      /* 
      *  needs another check or two, like altering the base case a bit
      *  the point should be clear, though.
      */
      

      它会有点乱,但它会完成这项工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多