2

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

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);
}

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

4

3 回答 3

4

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

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

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

于 2013-04-03T00:07:56.977 回答
1

维基百科关于该主题的文章

下面的伪代码显示了一个显式基于队列的实现。它类似于简单的递归解决方案,不同之处在于它不是进行递归调用,而是将节点推入 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.
于 2013-04-03T00:14:44.607 回答
1

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.
*/

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

于 2013-04-03T00:37:42.767 回答