洪水填充算法 - 迷宫导航

时间:2013-04-03 00:04:47

标签: c algorithm flood-fill

我正在尝试实现泛洪填充算法的一个版本,以帮助解决微型鼠标的迷宫的最短距离路径。它的工作方式与常规洪水填充的工作方式相同,不同之处在于每个相邻的非填充地点将分配一个数字,表示该地点到起始地点的距离。每次算法移动到不同的单元格时,该数字递增1。这是一个迷宫的例子,左下角没有墙壁。

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

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

3 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:1)

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.

答案 2 :(得分:1)

您在不测试任何条件的情况下致电north()。因此,您的递归将按顺序执行:

  • 1)测试基本情况
  • 2)设置新的洪水号码
  • 3)遇到//north并致电nav_flood_rec()
  • 4) REPEAT。

正如您所看到的,您永远不会接到其他电话。您需要实施测试条件,分支或类似的事情。

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

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

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