蓝桥杯-全球变暖
- 1、题目描述
- 2、解题思路
- 2.1 思路一:BFS
- 2.2 思路二:DFS
1、题目描述
你有一张某海域 NxN 像素的照片,".“表示海洋、”#"表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
.......
.......
.......
.......
....#..
.......
.......
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
输入描述
第一行包含一个整数N* (1≤N≤1000)。
以下 N 行 N 列代表一张海域照片。
照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋。
输出一个整数表示答案。
输入输出样例
示例
输入
7
.......
.##....
.##....
....##.
..####.
...###.
.......
输出
1
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
2、解题思路
2.1 思路一:BFS
我们用BFS
统计不会被淹没的岛屿个数,每次搜索的时候,判断上下左右是不是都是陆地,若是,则这个岛屿不会被淹没,最后我们用岛屿总数-不会被淹没的岛屿个数即可。
这里注意一下,被海洋覆盖之后,不会被淹淹没的岛屿数量可能会增加。
还有,如果初始的时候,一个陆地的周围都是海洋,这个陆地也是可以构成岛屿的,这个很关键,刚开始不知道这个,走了很多弯路,不过这个条件感觉有点歧义。
定义四个方向:
//定义方向
public static int[][] dirs={
{0,1}, //右
{1,0}, //下
{0,-1}, //左
{-1,0} //上
};
我们直接对每一个岛屿使用BFS即可,用一个标志位sign
记录该岛屿是否会被淹没,如果不会被淹没,设置sign=true
,我们设置ans++
来统计不会被淹没的岛屿数量。每次遍历岛屿的时候,用sum++
来统计岛屿总数
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
,看个人习惯吧。