全球变暖【蓝桥杯】【算法设计与分析】【BFS】
问题描述:
你有一张某海域 N×N像素的照片,”.”表示海洋、”#”表示陆地,如下所示:
…
.##…
.##…
…##.
…####.
…###.
…
其中”上下左右”四个方向上连在一起的一片陆地组成一座岛屿,例如上图就有 2座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。
具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
…
…
…
…
…#…
…
…
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
解题算法思路:
- 用bfs(不会重复)遍历一片连续的陆地,判断靠海的陆地个数和总陆地的个数的关系:如果靠海的陆地个数等于总陆地个数,则该岛屿会消失;否则不会消失。此处只有等于和小于的情况,没有大于的情况。
源代码
1.import java.io.IOException;
2.import java.util.LinkedList;
3.import java.util.Queue;
4.import java.util.Scanner;
5.
6.public class globalWarming {//全球变暖 广度优先遍历
7. public static Queue<Point> queue = new LinkedList<Point>();
8. public static char area[][] = new char[1000+1][1000+1];//存放整个图片像素
9. public static int vis[][] = new int[1000+1][1000+1];//该陆地是否访问过
10. public static class Point{
11. int x,y;
12. public Point(int x,int y) {
13. this.x=x;
14. this.y=y;
15. }
16. }
17. public static boolean check(int x,int y) {//检查陆地是否靠海
18. if(area[x-1][y]=='.'||area[x+1][y]=='.'
19. ||area[x][y-1]=='.'||area[x][y+1]=='.')
20. return true;
21. return false;
22. }
23.
24. public static boolean bfs(int x,int y) {//广度优先遍历不会重复
25. queue.offer(new Point(x, y));//将没访问过的陆地放入队列中
26. vis[x][y]=1;//设为已访问
27. int sea=0,land=0;//sea靠海的陆地个数,land陆地总数
28. int next[][] = {{-1,0},{1,0},{0,-1},{0,1}};//上下左右
29. while(!queue.isEmpty()) {
30. Point p =queue.poll();//取出队列第一个元素
31. land++;
32. if(check(p.x,p. y)) {
33. sea++;
34. }
35. for(int i=0;i<4;i++) {//遍历该陆地上下左右的区域,如果有未访问过的邻接点,则存入队列中
36. int r =p.x+next[i][0];
37. int c =p.y+next[i][1];
38. if(area[r][c]=='#'&&vis[r][c]==0) {
39. queue.offer(new Point(r, c));
40. vis[r][c]=1;
41. }
42. }
43. }
44. if(sea==land)return true;//靠海的陆地个数=陆地总数,则会被淹没
45. return false;
46. }
47.
48. public static void main() throws IOException {
49.
50. Scanner sc =new Scanner(System.in);
51. int n=sc.nextInt();
52. int num=0;//存放消失的岛屿数
53. for(int i=1;i<=n;i++) {
54. String str = sc.next();
55. char c[] = str.toCharArray();//一行字符串读入并转为字符数组
56. for(int j=1;j<=n;j++) {
57. area[i][j]=c[j-1];//第i行字符数组依次存入二维数组第i行
58. }
59. }
60. for(int i=1;i<=n;i++) {
61. for(int j=1;j<=n;j++) {
62. if(area[i][j]=='#'&&vis[i][j]==0) {//这是一块没访问过的陆地
63. if(bfs(i,j)) {//如果靠海的陆地数等于陆地总数,则该岛屿会消失
64. num++;
65. }
66. }
67. }
68. }
69. System.out.println("照片中有"+num+"座岛屿会被完全淹没");
70. UI.main();
71. }
72.
73.}
算法效率分析:
- 由于使用的是广度优先遍历,它有一个特点就是不会重复,只要一遍历到正确答案就会返回。所以效率也还算可以,时间复杂度应该是O(n)