深度优先算法:最大的油田
政府现勘探到一片油田,在这一片油田中有很多散落的石油资源。因为经费原因,政府只能开采一处油田,所以需找到最大的油田进行施工。油田的地理情况被简化成了一个矩阵,其中每一个方格代表一块土地,0代表陆地,1代表石油资源。如果一处石油资源和另一处石油相连接,则其算一块油田。现要找到最大的相互连接的石油资源,并输出它的面积。
如上图所示,就是一个例子,其中灰色的区域都是不同大小的油田。那么对于这个例子来说,左上角的五块石油连在一起的区域就是最大的油田,其面积为5,如下图所示。
首先,我们分析一下这个问题。问题是找到最大的油田,所以需把每个岛屿的面积算出来,然后比较,在其中找出最大的即可。为了知道一块油田有多大,我们可能需遍历每一个图中的方格。但如果只是单纯的按上下左右的顺序遍历的话效率低而且难获取答案。不过我们知道,在一块油田中,石油资源一定是相邻的,因此只有四中情况:上,下,左,右。所以结合深度优先遍历算法,我们可以对每一个方格进行搜索来寻找该方格相邻处是否还有石油资源。但要注意的是,搜索需不重不漏,所以已经搜索过的地方需被标记,以免被重复搜到。以下即为搜索前的处理代码:
def MaxAreaOfIsland(grid): #grid为题目给的二维数组,其中存储着地理信息
row = len(grid) #row记录二维数组的行数,也是地图的y轴长度
col = len(grid[0]) #col记录二维数组的列数,也是地图的x周长度
arrived = [[False for j in range(col)] for i in range(row)]
#arrived为一个二维数组,存储一块土地是否被访问过
ans = 0
return ans
现在就可以开始用深度优先遍历算法测算油田的最大面积了。我们可以用循环依次以每一块土地为起点进行搜索。如果该块土地含有石油资源,则继续搜索,反之则继续循环遍历其他土地
来看一个例子,如下图所示,最先找到的石油资源是被填充为黑色的土地。
接下来我们需要向它的四个方向查找。如果向上,土地就超出地图的边界了,所以搜索无果。如果向左,该区域其实已经被搜索,且值为0,没有石油资源。如果向下,发现没有越出地图边界,并且含有石油资源,这时在搜索我们移动到下面的点。
此时来到下面的土地处,还要遵循一样的顺序,先尝试向上走,发现上面为已经访问过的陆地,继而向左搜索,发现左处不含有石油资源,再尝试向右搜索,搜索到了石油资源,并以右处的方格继续开始新的搜索。如此反复,可将整幅图搜索完,求解出答案。
为此,我们重新定义一个新的函数来进行深度优先遍历算法,在避免越界和重复访问的条件下,向四个不同的方向递归调用搜素代码如下所示:
#深度优先代码
def DFS(x, y,grid):
row = len(grid) # row记录二维数组的行数,也是地图的y轴长度
col = len(grid[0]) # col记录二维数组的列数,也是地图的x周长度
arrived = [[False for j in range(col)] for i in range(row)]
# arrived为一个二维数组,存储一块土地是否被访问过
ans = 0
if x >= 0 and x < row and y >= 0 and y < col and not arrived[x][y] and grid[x][y] == 1:
arrived[x][y] = True
return 1 + DFS(x - 1, y) + DFS(x + 1, y) + DFS(x, y - 1) + DFS(x, y + 1)
else:
return 0
最后在主函数中调用这个深度优先遍历函数即可。
最终代码
综合以上分析,合并成完整代码。
#最大的油田代码
def MaxAreaOfIsland(grid): #grid为题目给的二维数组,其中存储着地理信息
row = len(grid) #row记录二维数组的行数,也是地图的y轴长度
col = len(grid[0]) #col记录二维数组的列数,也是地图的x周长度
arrived = [[False for j in range(col)] for i in range(row)]。#arrived为一个二维数组,存储一块土地是否被访问过
ans = 0 #记录油田的最大面积
def DFS(x, y):
if x >= 0 and x < row and y >= 0 and y < col and not arrived[x][y] and grid[x][y] == 1: #判断现在搜索的土地是否出界,是否已经访问过,和是否含有石油资源
arrived[x][y] = True #标记该快土地已经被搜索
return 1 + DFS(x - 1, y) + DFS(x + 1, y) + DFS(x, y - 1) + DFS(x, y + 1) #搜索其相邻的土地并将答案加上1
else:
return 0
for i in range(row):
for j in range(col):
area = DFS(i, j) #遍历搜索每一块土地
if area > ans:
ans = area
return ans
小结
最大的油田问题,本质上为图上的深度优先问题。每个结点都有上下左右四个方向需要递归。
长按识别下方二维码,和众多位岛民一起
把别人的顿悟,变成你的基本功
花半秒钟就看透事物本质的人,
和花一辈子都看不清的人,
注定是截然不同的命运。