由种子填充法谈两种基本搜索的实现

    技术2022-05-20  35

             所谓种子填充法,就是常见的基本算法floodfill的中文名字。就像一滴墨水浸到宣纸之上,渐渐扩散。使用两种基本搜索——DFSBFS可以实现这种算法。下面我通过数据结构的层面来介绍一下DFSBFS的实现。

             首先来介绍“树”。计算机中的树和现实生活中的树相反——它的跟在上面,叶子在下面。相连的连个节点互为父子,同一高度的节点互为兄弟。如图:

     

             比如说:2,3,4节点互为兄弟;5,6节点是2节点的儿子;7节点是10,11节点的父亲。

             我们可以把DFSBFS分别看作在这棵树上的遍历(什么是遍历请自行解决)。那么DFS所经过的路径和BFS所经过的路径就如下图所示:

     

             当然我们可以把这两个过程分别在“堆栈”和“队列”中实现。什么叫“堆栈”和“队列”呢?

             “堆栈”的特点是FILOfirst in last out)。堆栈有一个栈顶(top),两种操作入栈(push)和出栈(pop)。我们将新的元素插入栈顶,也从栈顶弹出元素。这个过程就像DFS一样。而DFS的递归实现本身就是在“系统栈”中进行的。

             “队列”的特点是FIFO(first in first out)。队列有一个头(head)一个尾(tail)。在队尾插入新的元素(enqueue),在队头弹出元素(dequeue)。

             需要注意的是,我们在插入元素是要查看堆栈和队列是否会溢出,删除时要看是否为空。

     

             接下来,我们说说DFSBFS的实际应用和实现。就举种子填充法这个例子吧!这是一道IOI94的题目。我们看看一道IOI的题目是如何被我们解决的!

             在一个n*m的房子中有被墙分割的几个房间。对于每个单位空间我们用几个数字加和代表它周围墙的布局。我们用1代表西,2代表北,3代表东,4代表南。比如用 @表示出的(2,4)区域可以描述为1 + 4 + 8 = 13

     

         1   2   3   4   5   6   7

       #############################

     1 #   |   #   |   #   |   |   #

       #####---#####---#---#####---#  

     2 #   #   |   # @ #   #   #   #

       #---#####---#####---#####---#

     3 #   |   |   #   #   #   #   #  

       #---#########---#####---#---#

     4 #   #   |   |   |   |   #   #  

       #############################

     

             现在给你对于一个房子每个单位空间的描述,求出有多少个独立的房间和最大房间的面积。

     

     

             首先,我们尝试用DFS解决

             我们想到依次对每个单位空间进行floodfill,如果遇到了墙的阻碍,那么扩展就要停止。我们使用一个布尔数组来判断这个单位空间是否已经被访问。这个数组的作用我们叫做“判重”。扩展的过程就是递归地对周围四个方向允许被访问的区域再进行floodfill……

     

             这里的check是一个布尔函数,如何设计请自行分析。

             同样,用BFS也可以实现这个算法。我的习惯是使用一个记录类型的数组来实现队列。套用BFS的框架即可:

     

     

             这样,就把大体的框架展现出来了。当然,如果想解决这的题目也需要进行必要的完善,希望能自行解决这道题目!另外,题目的完整版还有另外两问,感兴趣的同学可以到以下链接查看:

    http://www.nocow.cn/index.php/Translate:USACO/castle

             题目的提交可以直接在USACO中进行!


    最新回复(0)