FloodFill.docx

上传人:b****5 文档编号:3909792 上传时间:2022-11-26 格式:DOCX 页数:8 大小:20.36KB
下载 相关 举报
FloodFill.docx_第1页
第1页 / 共8页
FloodFill.docx_第2页
第2页 / 共8页
FloodFill.docx_第3页
第3页 / 共8页
FloodFill.docx_第4页
第4页 / 共8页
FloodFill.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

FloodFill.docx

《FloodFill.docx》由会员分享,可在线阅读,更多相关《FloodFill.docx(8页珍藏版)》请在冰豆网上搜索。

FloodFill.docx

FloodFill

FloodFill

种子染色法 

译byLuckyCrazy &FeliciaCrazy

(FloodFill按原意应翻译成“水流式填充法”(如果我没译错),有些中文书籍上将它称作“种子染色法”,然而大部分的书籍(包括中文书籍)都直接引用其英文原名:

FloodFill。

介于此,下文所有涉及到FloodFill的都直接引用英文——译者)

样例:

相连的农场

FarmerJohn的农场被一次意外事故破坏了,有一些农场与其他的农场之间有道路相连,而有些道路却已被破坏。

这使得FarmerJohn无法了解到从一个农场能否到达另一个农场。

你的任务就是帮助FarmerJohn来了解哪些农场是连通的。

 

给出:

上题实际上就是要求寻找一张无向图的所有极大连通子图。

给出一张未知连通性的图,如下图:

可知,该图的极大连通子图是:

{1,4,8},{2,5,6,7,9}和 {3}。

算法:

FloodFill

FloodFill可以用深度优先搜索,广度优先搜索或广度优先扫描来实现。

他的实现方式是寻找到一个未被标记的结点对它标记后扩展,将所有由它扩展出的结点标上与它相同的标号,然后再找另一个未被标号的结点重复该过程。

这样,标号相同的结点就属于同一个连通子图。

深搜:

取一个结点,对其标记,然后标记它所有的邻结点。

对它的每一个邻结点这么一直递归下去完成搜索。

广搜:

与深搜不同的是,广搜把结点加入队列中。

广度扫描(不常见):

每个结点有两个值,一个用来记录它属于哪个连通子图(c),一个用来标记是否已经访问(v)。

算法对每一个未访问而在某个连通子图当中的结点扫描,将其标记访问,然后把它的邻结点的(c)值改为当前结点的(c)值。

深搜最容易写,但它需要一个栈。

搜索显式图没问题,而对于隐式图,栈可能就存不下了。

广搜稍微好一点,不过也存在问题。

搜索大的图它的队列有可能存不下。

深搜和广搜时间复杂度均为O(N+M)。

其中,N为结点数,M为边数。

广度扫描需要的额外空间很少,或者可以说根本不要额外空间,但是它很慢。

时间复杂度是O(N^2+M)。

(实际应用中,我们一般写的是DFS,因为快。

空间不是问题,DFS可改用非递归的栈操作完成。

但为了尊重原文,我们还是译出了广度扫描的全过程。

——译者)

广度扫描的伪代码

代码中用了一个小技巧,因此无须额外空间。

结点若未访问,将其归入连通子图(-2),就是代码里的component-2。

这样无须额外空间来记录结点是否访问,请读者用心体会。

# component(i) denotes the

# component that node i is in

 1 function flood_fill(new_component) 

 2 do

 3   num_visited = 0

 4   for all nodes i

 5     if component(i) = -2

 6       num_visited = num_visited + 1

 7       component(i) = new_component

 8       for all neighbors j of node i

 9         if component(j) = nil

10           component(j) = -2

11 until num_visited = 0 

12 function find_components 

13  num_components = 0

14  for all nodes i

15    component(node i) = nil

16  for all nodes i

17    if component(node i) is nil

18      num_components =

                 num_components + 1

19      component(i) = -2

20      flood_fill(component

                        num_components)

算法的时间复杂度是O(N2),每个结点访问一次,每条边经过两次。

实例

考虑刚才的那张图:

开始时,所有的结点都没有访问。

(下例中未访问被表示为-2)

首先从结点1开始,结点1未访问,那么先处理结点1,将它归入连通子图1。

结点

连通子图

1

-2

标记完成后,对它进行第一步的扩展,由结点4和结点8与结点1连通,故它们被扩展出来。

结点

连通子图

1

1

4

-2

8

-2

之后,先处理结点4,将它与结点1归入相同的连通子图。

现在它没有可扩展的结点了(结点1已被扩展过)

 

结点

连通子图

1

1

4

1

8

-2

接着处理结点8。

结果与结点4一样。

结点

连通子图

1

1

4

1

8

1

现在,所有与结点1连通的结点都已扩展,标号为1的连通子图产生了。

那么我们将跳出扩展步骤,寻找下一个连通子图,标号为2。

与上一步相同的顺序,找到结点2。

结点

连通子图

1

1

2

-2

4

1

8

1

扩展结点2,结点7与结点9出现。

结点

连通子图

1

1

2

2

4

1

7

-2

8

1

9

-2

下一步,扩展结点7,结点5出现。

结点

连通子图

1

1

2

2

4

1

5

-2

7

2

8

1

9

-2

然后是结点9。

结点

连通子图

1

1

2

2

4

1

5

-2

7

2

8

1

9

2

扩展结点5。

结点6出现。

结点

连通子图

1

1

2

2

4

1

5

2

6

-2

7

2

8

1

9

2

很遗憾,结点6没有可供扩展的结点。

至此连通子图2产生。

 

结点

连通子图

1

1

2

2

4

1

5

2

6

2

7

2

8

1

9

2

之后寻找连通子图3,至此,仅有结点3未被扩展。

 

结点

连通子图

1

1

2

2

3

-2

4

1

5

2

6

2

7

2

8

1

9

2

结点3没有可供扩展的结点,这样,结点3就构成了仅有一个结点的连通子图3。

 

结点

连通子图

1

1

2

2

3

3

4

1

5

2

6

2

7

2

8

1

9

2

结点3处理结束后,整个图的所有9个结点就都被归入相应的3个连通子图。

FloodFill结束。

问题提示

这类问题一般很清晰,求解关于“连通”的问题会用到FloodFill。

它也很经常用作某些算法的预处理。

扩展与延伸

有向图的连通性比较复杂。

同样的填充算法可以找出从一个结点能够到达的所有结点。

每一层递归时,若一个结点未访问,就将其标记为已访问(表示他可以从源结点到达),然后对它所有能到达且为访问的结点进行下一层递归。

若要求出可以到达某个结点的所有结点,你可以对后向弧做相同的操作。

例题

控制公司[有删节,IOI93]

已知一个带权有向图,权值在0-100之间。

如果满足下列条件,那么结点A“拥有”结点B:

∙A=B

∙从A到B有一条权值大于50的有向弧。

∙存在一系列结点C1到Ck满足A拥有C1到Ck,每个节点都有一条弧到B,记作x1,x2...xk,并且x1+x2+...+xk>50。

找出所有的(A,B)对,满足A拥有B。

分析:

这题可以用上面提到的“给出一个源,在有向图中找出它能够到达的结点”算法的改进版解决。

要计算A拥有的结点,要对每个结点计算其“控股百分比”。

把它们全部设为0。

现在,在递归的每一步中,将其标记为属于A并把它所有出弧的权加到“控股百分比”中。

对于每个“控股百分比”超过50的结点,进行同样的操作(递归)。

 

街道赛跑[IOI95]

已知一个有向图,一个起点和一个终点。

找出所有的p,使得从起点到终点的任何路径都必须经过p。

分析:

最简单的算法是枚举p,然后把p删除,看看是否存在从起点到终点的通路。

时间复杂度为O(N(M+N))。

题目的数据范围是M<=100,N<=50,不会超时。

牛路[1999USACO国家锦标赛,有删节]

连通图的直径定义为图中任意两点间距离的最大值,两点间距离定义为最短路的长。

已知平面上一个点集,和这些点之间的连通关系,找出不在同一个连通子图中的两个点,使得连接这两个点后产生的新图有最小的直径。

分析:

找出原图的所有连通子图,然后枚举不在同一个连通子图内的每个点对,将其连接,然后找出最小直径。

笨蛋建筑公司

FarmerJohn计划建造一个新谷仓。

不幸的是,建筑公司把他的建造计划和其他人的建造计划混淆了。

FarmerJohn要求谷仓只有一个房间,但是建筑公司为他建好的是有许多房间的谷仓。

已知一个谷仓平面图,告诉FarmerJohn它一共有多少个房间。

分析:

随便找一个格子,遍历所有与它连通的格子,得到一个房间。

然后再找一个未访问的格子,做同样的工作,直到所有的格子均已访问。

虽然题目给你的不是直接的图,但你也可以很容易地对其进行FloodFill。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 数学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1