[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第90讲。
无污染的独立海域,本题是2022年4月23日举办的第13届蓝桥杯青少组Python编程省赛真题编程部分第5题,13届一共举办了两次省赛,这是第二次省赛。题目要求对于给定的N * M个方格数据,请编程计算没被污染的独立海域的数量。
先来看看题目的要求吧。
一.题目说明
时间限制:3000MS
内存限制:589824K8
编程实现:
有一片海域划分为N * M个方格,其中有些海域已被污染(用0表示),有些海域没被污染(用1表示)。请问这片N * M海域中有几块是没被污染的独立海域(没被污染的独立海域是指该块海域上下左右被已污染的海域包围,且N * M以外的海域都为已被污染的海域)
例如:N = 4,M = 5,4 * 5的海域中,已被污染海域和没被污染的海域如下图:
这块4 * 5的海域,有3块海域(绿色)没被污染,因为每一块的上下左右都被污染的海域包围。
输入描述:
第一行输入两个正整数N和M,N表示矩阵方格的行,M表示矩阵方格的列,N和M之间以一个英文逗号隔开
第二行开始输入N行,每行M个数字(数字只能为1或者0,1表示没被污染的海域,0表示已被污染的海域)
输出描述:
输出一个整数,表示N * M的海域中有几块是没被污染的独立海域
样例输入:
4,5
1,1,0,0,0
1,0,1,0,0
1,0,0,0,0
1,1,0,1,1
样例输出:
3
评分标准:
-
20分:能正确输出一组数据;
-
20分:能正确输出两组数据;
-
20分:能正确输出三组数据;
-
20分:能正确输出四组数据。
二.思路分析
这是一道经典的算法题,涉及的知识点包括循环、条件、二维列表和DFS算法等。
又是经典的岛屿问题,和4月17日第一次省赛的第6题如出一辙,可以参考《独立农作物区域-第13届蓝桥杯省赛Python真题精选》这篇教程。
解决这类问题的通用方法就是DFS算法,DFS算法的核心思想是尽可能深地探索图的分支,直到无法继续为止,然后回溯并探索其他分支,在代码层面,主要是通过递归来实现。
具体的过程分析,这里就不再赘述了,可以直接参考农作物区域那道题。
此处,我要强调的是在解决岛屿问题时,DFS函数的抽象意义。抛开具体的代码层面,我们要深入理解DFS函数到底干了些什么?
简单来说,就两件事情,如下:
-
如果当前单元格是岛屿,就使用递归算法,找到与之相连的岛屿单元格;
-
每找到一个岛屿单元格,就将其淹掉,变成水域;
所以,DFS函数通常也叫淹掉函数,或者叫感染函数,就像病毒一样,一旦找到一个健康的细胞,就迅速地将其感染,并立即扩散到周围所有的细胞。
思路有了,接下来,我们就进入具体的编程实现环节。
三.编程实现
根据上面的思路分析,我们分两步编写程序:
-
定义DFS函数
-
统计无污染海域数量
1. 定义DFS函数
根据前面的思路分析,定义DFS函数如下:
代码不多,说明两点:
1). 针对给定的单元格,如果i和j越界了,直接返回,如果当前没有被污染,也直接返回,这是递归的两个出口,需要注意顺序,也可以合并为一个;
2). 如果当前是无污染的海域,则先将其淹掉,然后向4个方向递归处理,同样要注意二者的顺序,要先淹掉,避免陷入死循环。
2. 统计无污染海域数量
按照从上到下、从左到右的顺序遍历每一个单元格,代码如下:
代码不多,说明两点:
1). grid是一个n x m的二维列表,先构造一个长度为n的一维列表,然后再使用循环将输入的每一行数字,保存到列表中,构成二维列表;
2). 统计无污染的独立海域时,需要遍历每一个单元格,如果当前区域是独立海域,就说明找到了一块独立海域,将count增加1,然后调用dfs函数将这一片海域都淹掉。
至此,整个程序就全部完成了,你可以输入不同的数据来测试效果啦。
四.总结与思考
本题代码在23行左右,涉及到的知识点包括:
-
循环语句;
-
条件语句;
-
二维列表;
-
枚举算法;
-
递归函数;
-
DFS算法;
本题分数为80分,代码不少,难度也比较大。关键点有两个,一是对递归函数的理解和运用,二是对DFS函数的深入理解。
DFS函数是本题的重点,我们不能仅仅停留在具体的代码层面,而是要将其抽象出来,深入理解其作用。建议大家多使用淹掉函数(或感染函数)来描述,形象生动,便于理解。
所有岛屿问题的解决方法都是类似的,而DFS函数是解决这类问题的关键。因此,一定要深入理解并掌握DFS函数的定义及使用。
你还有什么好的想法和创意吗,也非常欢迎和超平老师分享探讨。
如果你觉得文章对你有帮助,别忘了点赞和转发,予人玫瑰,手有余香😄
需要源码的,可以移步至“超平的编程课”gzh。