这是我参与更文挑战的第5天,活动详情查看: [更文挑战]
你好呀,我是灰小猿,一个超会写bug的程序猿!
欢迎大家关注我的专栏“每日蓝桥”,该专栏的主要作用是和大家分享近几年蓝桥杯省赛及决赛等真题,解析其中存在的算法思想、数据结构等内容,帮助大家学习到更多的知识和技术!
标题:全球变暖
你有一张某海域 N×N像素的照片,”.”表示海洋、”#”表示陆地,如下所示:
其中”上下左右”四个方向上连在一起的一片陆地组成一座岛屿,例如上图就有 2座岛屿。 由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。
具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
输入格式
第一行包含一个整数N。
以下 N行 N 列,包含一个由字符”#”和”.”构成的 N×N字符矩阵,代表一张海域照片,”#”表示陆地,”.”表示海洋。照片保证第 1行、第 1 列、第 N 行、第 N列的像素都是海洋。
输出格式
一个整数表示答案。
数据范围
1≤N≤1000
输入样例1:
7
.......
.##....
.##....
....##.
..####.
...###.
.......
输出样例1:
1
输入样例2:
9
.........
.##.##...
.#####...
.##.##...
.........
.##.#....
.#.###...
.#..#....
.........
输出样例2:
1
资源约定: .
峰值内存消耗(含虚拟机) < 256M
CPU消耗< 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“ 请您输...”的多余内容.
所有代码放在同-一个源文件中,调试通过后,拷贝提交该源码.
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是: Main, 否则按无效代码处理.
解题思路
本题在求解的时候其实主要就是判断有哪几个陆地是在同一个岛屿上的,其实就是二维数组连通块的判断问题,判断出有哪几个块是共同组成了一个岛屿之后,很多同学可能会想着看看每一块是否是靠海的,其实这样的解决原则是没有问题的,但是具体在实践的过程中其实是不好解决的,
所以我们可以直接在判断该块是否是与其他块连通的时候,就可以判断该陆地块的周围是不是海洋,我们可以定义两个变量,cnt1表示该岛屿所有陆地的数量,cnt2表示该岛屿上靠海陆地的数量,在找完该岛屿上所有的陆地块之后,我们判断所有陆地数量和靠海陆地数量是否相等,即cnt1是否等于cnt2,如果等于,则说明所有陆地都是靠海的,那么该岛屿一定会被淹没。
至于连通块的判断,其实是使用了BFS广度搜索的思路,每走过一个区域,就标记该区域不能再走,直到走完所有的块为止。
答案源码:
package 一八年省赛真题; import java.awt.Point; import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; public class Year2018_Bt9 { static int N; static int[][] mark; static char[][] mapData; static int ans=0; static int[] tox = {-1,0,1,0}; static int[] toy = {0,1,0,-1}; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); N = scanner.nextInt(); scanner.nextLine(); mark = new int[N][N]; mapData = new char[N][N]; for (int i = 0; i < N; i++) { String info = scanner.nextLine(); mapData[i] = info.toCharArray(); } for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { //如果该点是陆地且未被访问 if (mapData[i][j]=='#' && mark[i][j]==0) { bfs(i,j); } } } System.out.println(ans); } /**广度优先搜索算法 * 遍历连通块 * */ private static void bfs(int x, int y) { mark[x][y] = 1; //表示该点已经访问过 int cnt1 = 0; //表示总陆地数 int cnt2 = 0; //表示靠近海洋的陆地数 Queue<Point> queue = new LinkedList<Point>();//建立队列,存放一个点类 queue.add(new Point(x, y)); //如果队列不为空 while(!queue.isEmpty()) { Point point = queue.poll(); //取出队列头元素 boolean isKaoHai = false; //表示该块陆地靠海 cnt1++; //遍历四个方向 for (int i = 0; i < 4; i++) { int newx = point.x + tox[i]; int newy = point.y + toy[i]; if(mapData[newx][newy]=='.') isKaoHai = true; //如果相邻的是陆地,且未被探索 if (mapData[newx][newy]=='#' && mark[newx][newy]==0) { queue.add(new Point(newx, newy));//将新的陆地加入队列 mark[newx][newy] = 1; } } if (isKaoHai) cnt2++; //如果靠海,则靠海的陆地数量加一 } //如果靠海的陆地数和总的陆地数相等,则岛屿全部淹没 if (cnt1==cnt2) ans++; } }
输出样例:
其中有不足或者改进的地方,还希望小伙伴留言提出,一起学习!
感兴趣的小伙伴可以关注专栏!
灰小猿陪你一起进步!