蓝桥杯-全球变暖

  • 1、题目描述
  • 2、解题思路
  • 2.1 思路一:BFS
  • 2.2 思路二:DFS

1、题目描述

  你有一张某海域 NxN 像素的照片,".“表示海洋、”#"表示陆地,如下所示:

.......
.##....
.##....
....##.
..####.
...###.
.......

  其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 座岛屿。

  由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

  例如上图中的海域未来会变成如下样子:

.......
.......
.......
.......
....#..
.......
.......

  请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。

输入描述

  第一行包含一个整数N* (1≤N≤1000)。

  以下 NN 列代表一张海域照片。

  照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋。

  输出一个整数表示答案。

输入输出样例

示例

输入

7
.......
.##....
.##....
....##.
..####.
...###.
.......

输出

1

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

2、解题思路

2.1 思路一:BFS

  我们用BFS统计不会被淹没的岛屿个数,每次搜索的时候,判断上下左右是不是都是陆地,若是,则这个岛屿不会被淹没,最后我们用岛屿总数-不会被淹没的岛屿个数即可。

蓝桥杯-全球变暖(BFS/DFS)_dfs

   这里注意一下,被海洋覆盖之后,不会被淹淹没的岛屿数量可能会增加。

   还有,如果初始的时候,一个陆地的周围都是海洋,这个陆地也是可以构成岛屿的,这个很关键,刚开始不知道这个,走了很多弯路,不过这个条件感觉有点歧义。

  定义四个方向:

蓝桥杯-全球变暖(BFS/DFS)_bfs_02

//定义方向
public static int[][] dirs={
        {0,1},  //右
        {1,0},  //下
        {0,-1}, //左
        {-1,0}  //上
};

  我们直接对每一个岛屿使用BFS即可,用一个标志位sign记录该岛屿是否会被淹没,如果不会被淹没,设置sign=true,我们设置ans++来统计不会被淹没的岛屿数量。每次遍历岛屿的时候,用sum++来统计岛屿总数

蓝桥杯-全球变暖(BFS/DFS)_深度优先_03

import java.io.*;
import java.util.LinkedList;

/**
 * 方案一:BFS
 * 统计不会被淹没的岛屿个数
 * 每次搜索的时候,判断是否存在上下左右都是陆地,若是,则这个岛屿不会被淹没
 *
 * 最后被淹没的岛屿数量=岛屿总数-不会被淹没的岛屿个数
 *
 * 开始的时候找到一个陆地并且没有访问过的时候就将岛屿总数+1,然后BFS,
 * 因为BFS会将其周围的点设置为已经访问,一次BFS会将一个岛屿的节点都扩展完毕
 * 注意:这里被海洋覆盖之后,不会被淹没的岛屿数量可能会增加。
 */
public class Main {
    public static long sum;//总岛屿数量
    public static long ans;//不会被淹没的岛屿数量
    public static boolean sign=false;//不会被淹没的岛屿标记
    public static char[][] map;//标记数据是海洋还是陆地
    public static boolean[][] visited;//标记是否已经访问过
    public static int n;
    //定义方向
    public static int[][] dirs={
            {0,1},  //右
            {1,0},  //下
            {0,-1}, //左
            {-1,0}  //上
    };
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        n = Integer.parseInt(in.readLine());
        map = new char[n][n];
        visited=new boolean[n][n];
        for (int i = 0; i <n ; i++) {
            map[i]=in.readLine().toCharArray();
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                //该点是陆地且没有被访问过
                if(map[i][j]=='#'&&!visited[i][j]){ //其实是在搜索岛屿
                    sum++;  //计算岛屿总数
                    sign=false;
                    bfs(i,j);
                    if(sign){
                        ans++;  //统计不会被淹没的岛屿数量
                    }
                }
            }
        }
        //会被淹没的岛屿数量=总岛屿数量-不会被淹没的岛屿数量
        ans=sum-ans;
        out.print(ans);
        in.close();
        out.flush();
        out.close();
    }
    public static void bfs(int x,int y){
        LinkedList<Point> queue = new LinkedList<>();
        queue.offer(new Point(x,y));
        visited[x][y]=true;
        while(!queue.isEmpty()){
            Point point = queue.poll();
            if(check(point.x,point.y)){
               sign=true;  //不会被淹没
            }
            for (int[] dir : dirs) {
                int tx = point.x + dir[0];
                int ty = point.y + dir[1];
                if(tx<0||tx>n-1||ty<0||ty>n-1){//判断是否越界
                    continue;
                }
                if(map[tx][ty]=='.'||visited[tx][ty]){//如果是海洋或者已经访问过了
                    continue;
                }
                visited[tx][ty]=true;
                queue.offer(new Point(tx,ty));
            }
        }
    }
    //校验岛屿是否不会被淹没:只有和海洋乡里你的都会被淹没
    //true:不会被淹没  false:会被淹没
    public static boolean check(int x,int y){
        for (int[] dir : dirs) {
            int tx = x + dir[0];
            int ty = y + dir[1];
            if(tx<0||tx>n-1||ty<0||ty>n-1){
                continue;
            }
            if(map[tx][ty]=='.'){
                return false;
            }
        }
        return true;
    }
}
class Point{
    int x;
    int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

2.2 思路二:DFS

  这个跟上面的思路差不多,我个人也更倾向于使用BFS来解决问题。

import java.io.*;

/**
 * 方案一:DFS
 * 一共有多少座岛屿:dfs搜索岛屿
 * 搜索的过程中统计不会被淹没的岛屿数量,最后用岛屿总数-不会被淹的岛屿数量
 * 就得到了被淹没的岛屿总数
 */
public class Main1 {
    public static boolean sign=false;//标记该岛屿是否不被淹没
    public static long num=0;//岛屿数
    public static long ans=0;//被淹没的岛屿数量
    public static char[][] map;//标记数据是海洋还是陆地
    public static boolean[][] visited;//标记是否已经访问过
    public static int n;    //地图边长
    //定义方向
    public static int[][] dirs={
            {0,1},  //右
            {1,0},  //下
            {0,-1}, //左
            {-1,0}  //上
    };
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        n = Integer.parseInt(in.readLine());
        map = new char[n][n];
        visited=new boolean[n][n];
        for (int i = 0; i <n ; i++) {
            map[i]=in.readLine().toCharArray();
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if(map[i][j]=='#'&&!visited[i][j]){
                    sign=false;
                    dfs(i,j,num);
                    if(sign){
                        ans++; //统计不会被淹没的岛屿数量
                    }
                    num++;  //统计岛屿总数
                }
            }
        }
        //被淹的数量=岛屿总数-不会被淹的岛屿数量
        out.println(num-ans);
        in.close();
        out.flush();
        out.close();
    }
    public static void dfs(int x,int y,long num){
        if(x<0||x>n-1||y<0||y>n-1){
            return;
        }
        if(map[x][y]=='.'||visited[x][y]){
            return;
        }
        if(check(x,y)){//该岛屿是否不会被淹没
            sign=true;
        }
        //设置为已访问
        visited[x][y]=true;
        //四个方向扩展
        for (int[] dir : dirs) {
            int tx = x + dir[0];
            int ty = y + dir[1];
            dfs(tx,ty,num);
        }
    }
    //校验岛屿是否不会被淹没:只有和海洋乡里你的都会被淹没
    //true:不会被淹没  false:会被淹没
    public static boolean check(int x,int y){
        for (int[] dir : dirs) {
            int tx = x + dir[0];
            int ty = y + dir[1];
            if(tx<0||tx>n-1||ty<0||ty>n-1){
                continue;
            }
            if(map[tx][ty]=='.'){
                return false;
            }
        }
        return true;
    }
}

蓝桥杯-全球变暖(BFS/DFS)_dfs_04

  我还是习惯用BFS,看个人习惯吧。