蓝桥杯第3513题——岛屿个数

解答代码

解题思路全在代码注释中,本题作者使用bfs方式作答

import java.util.*;
//1:无需package
//2: 类名必须Main, 不可修改

public class Main {
 public static void main(String[] args) {
     Scanner scan = new Scanner(System.in);
	 //T组数据,遍历T次
     int T = scan.nextInt();
     for(int p = 0; p < T; p++){
	   //岛屿的行数、列数
       int M = scan.nextInt();
       int N = scan.nextInt();
	   //岛屿矩阵
       int[][] island = new int[M][N];
	   //每个点的访问性,如果visited为true,代表该点是已被探明的岛屿
       boolean[][] visited = new boolean[M][N];
	   //记录每个岛屿的第一个点
       ArrayList<Pair> firstPoints = new ArrayList<>();
	   //bfs所用的队列
       Queue<Pair> queue = new ArrayDeque<>();
       int ans = 0;
	   //岛屿的寻找,需要向四个方向寻找相邻点
       int[] dx = {0,1,0,-1};
       int[] dy = {1,0,-1,0};
	   //岛屿矩阵的录入
       for(int i = 0; i < M; i++){
    	   String s = scan.next();
    	   char[] arr = s.toCharArray();
    	   for(int j = 0; j < N; j++) {
    		   island[i][j] = arr[j] - '0';
    	   }
       }
       //bfs岛屿数量添加
       for(int i = 0; i < M; i++){
         for(int j = 0; j < N; j++){
           if(island[i][j] == 1 && visited[i][j] == false){
             ans++;
             Pair firstPoint = new Pair(i,j);
             firstPoints.add(firstPoint);
             queue.offer(firstPoint);
             visited[i][j] = true;
             while(!queue.isEmpty()){
               Pair pair = queue.poll();
               for(int k = 0; k < dx.length; k++){
                 int x = pair.x + dx[k];
                 int y = pair.y + dy[k];
                 if(x >= 0 && x < M && y >= 0 && y < N){
                   if(island[x][y] == 1 && visited[x][y] == false){
                     queue.offer(new Pair(x,y));
                     visited[x][y] = true;
                   }
                 }
               }
             }
           }
         }
       }
	   //根据遍历方式可知,每个岛屿的第一个点有这样的特性
	   //该点的左和上两个方向上一定是海,且一定不会有该点所在岛屿的其他点
	   //因此只需要从这两个方向上的海出发,bfs搜索其连接海
	   //如果搜索时海坐标能到边界,说明这个岛屿不属于其他岛屿的子岛屿

	   //海域搜索的方向,每个点只要8个方向有一个能出去,就不是别人的子岛
	   //为什么不是4个方向请参考样例2中的3号岛屿
       int[] dxSea = {-1,-1,-1,0,0,1,1,1};
       int[] dySea = {1,0,-1,1,-1,1,0,-1};

       //子岛的判断,遍历所有岛屿的第一个点
	   outer:
       for(Pair point : firstPoints) {
		   //海的被访问性记录,对于每个岛屿单独记录
           boolean[][] visitedSea = new boolean[M][N];
		   //如果某个岛的第一个节点本身就在边界,肯定不是子岛,不必判断
    	   if(point.x != 0 && point.x != M-1 && point.y != 0 && point.y != N-1) {
    		   queue.clear();
			   //从岛屿第一个点的上方开始搜索海域
    		   queue.offer(new Pair(point.x-1, point.y));
    		   while(!queue.isEmpty()) {
    			   Pair temp = queue.poll();
				   //每个海节点必定会出队,判断出队的节点性质即可
    			   if(temp.x == 0 || temp.y == 0 || temp.x == M-1 || temp.y == N-1) {
					   //如果有海节点到达边界,说明该岛不是子岛,直接处理下一个节点
					   continue outer;
    			   }
    			   for(int k = 0; k < dxSea.length; k++) {
    				   int x = temp.x + dxSea[k];
    				   int y = temp.y + dySea[k];
					   //如果目标节点不越界,并且不是岛屿节点,也不是被访问过的海节点
    				   if(x >= 0 && x < M && y >= 0 && y < N) {
        				   if(visited[x][y] == false) {
        					   if(visitedSea[x][y] == false) {
								   //将该节点入队,并标记访问过
        						   queue.offer(new Pair(x,y));
        						   visitedSea[x][y] = true;
        					   }
        				   }
    				   }
    			   }
    		   }
    		   queue.clear();
			   //从岛屿第一个点的左方开始搜索海域,内容同上
    		   queue.offer(new Pair(point.x, point.y-1));
    		   while(!queue.isEmpty()) {
    			   Pair temp = queue.poll();
    			   if(temp.x == 0 || temp.y == 0 || temp.x == M-1 || temp.y == N-1) {
					   continue outer;
    			   }
    			   for(int k = 0; k < dxSea.length; k++) {
    				   int x = temp.x + dxSea[k];
    				   int y = temp.y + dySea[k];
    				   if(x >= 0 && x < M && y >= 0 && y < N) {
        				   if(visited[x][y] == false) {
        					   if(visitedSea[x][y] == false) {
        						   queue.offer(new Pair(x,y));
        						   visitedSea[x][y] = true;
        					   }
        				   }
    				   }
    			   }
    		   }
			   //如果所有海节点已经搜索完了,没有找到出路到达边界,说明是子岛屿,岛屿数量-1
    		   ans--;
    	   }
       }
       System.out.println(ans);
     }
     //在此输入您的代码...
     scan.close();
 }
}

class Pair{
	int x;
	int y;
	public Pair(int x, int y){
	 this.x = x;
	 this.y = y;
	}
	@Override
	public String toString() {
		return "Pair [x=" + x + ", y=" + y + "]";
	}
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值