当前位置: 首页 > article >正文

代码随想录-算法训练营-番外(图论03:孤岛的总面积,沉没孤岛,水流问题,建造最大岛屿)

day03 图论part03
今日任务:孤岛的总面积,沉没孤岛,水流问题,建造最大岛屿
代码总量有点多但是不难理解
https://www.programmercarl.com/kamacoder/0101.孤岛的总面积.html#思路
 

往日任务:
day01 图论part01 
今日任务:图论理论基础/所有可到达的路径
代码随想录图论视频部分还没更新
https://programmercarl.com/kamacoder/图论理论基础.html#图的基本概念

day02 图论part02
今日任务:岛屿数量,岛屿的最大面积
都是一个模子套出来的
https://programmercarl.com/kamacoder/0099.岛屿的数量深搜.html#思路
 

day03

孤岛的总面积

bfs如下,dfs不需要改变主函数

 //特殊之处在于直接在原地图grid上进行赋值,实现visited功能
 //以及在主函数中对贴边岛屿进行了消除处理
 import java.util.*;
 public class Main {
     private static int count = 0;//陆地面积
     private static final int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; // 四个方向
 ​
     private static void bfs(int[][] grid, int x, int y) {//广搜
         Queue<int[]> que = new LinkedList<>();
         que.add(new int[]{x, y});
         grid[x][y] = 0; // 只要加入队列,立刻标记
         count++;
         while (!que.isEmpty()) {//队列不为空,就取出来遍历四个方向判断合法性
         //如果不超边界而且是陆地,加进队列,设为0代表遍历过,count++
             int[] cur = que.poll();
             int curx = cur[0];
             int cury = cur[1];
             for (int i = 0; i < 4; i++) {
                 int nextx = curx + dir[i][0];
                 int nexty = cury + dir[i][1];
                 if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length) continue; // 越界了,直接跳过
                 if (grid[nextx][nexty] == 1) {
                     que.add(new int[]{nextx, nexty});
                     count++;
                     grid[nextx][nexty] = 0; // 只要加入队列立刻标记
                 }
             }
         }
     }
 ​
     public static void main(String[] args) {
         Scanner scanner = new Scanner(System.in);
         int n = scanner.nextInt();
         int m = scanner.nextInt();
         int[][] grid = new int[n][m];
         
         // 读取网格
         for (int i = 0; i < n; i++) {
             for (int j = 0; j < m; j++) {
                 grid[i][j] = scanner.nextInt();
             }
         }
         
         // 从左侧边,和右侧边向中间遍历
         //左右两边贴边的岛屿都设为0了
         for (int i = 0; i < n; i++) {
             if (grid[i][0] == 1) bfs(grid, i, 0);
             if (grid[i][m - 1] == 1) bfs(grid, i, m - 1);
         }
         
         // 从上边和下边向中间遍历
         //上下边界贴边的岛屿设为0
         for (int j = 0; j < m; j++) {
             if (grid[0][j] == 1) bfs(grid, 0, j);
             if (grid[n - 1][j] == 1) bfs(grid, n - 1, j);
         }
         
         count = 0;//计算孤岛面积
         for (int i = 0; i < n; i++) {
             for (int j = 0; j < m; j++) {
                 if (grid[i][j] == 1) bfs(grid, i, j);
                 //遍历剩下的岛屿,也就是孤岛
             }
         }
 ​
         System.out.println(count);
     }
 }

沉没孤岛

深搜,广搜只需要改变dfs即可

 //主函数:贴边岛屿设为2,然后遍历把1变成0 并且 把2变成1
 import java.util.Scanner;
 ​
 public class Main {
     static int[][] dir = { {-1, 0}, {0, -1}, {1, 0}, {0, 1} }; // 保存四个方向
 ​
     public static void dfs(int[][] grid, int x, int y) {
         grid[x][y] = 2;
         for (int[] d : dir) {
             int nextX = x + d[0];
             int nextY = y + d[1];
             // 超过边界
             if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) continue;
             // 不符合条件,不继续遍历
             if (grid[nextX][nextY] == 0 || grid[nextX][nextY] == 2) continue;
             dfs(grid, nextX, nextY);
         }
     }
 ​
     public static void main(String[] args) {
         Scanner scanner = new Scanner(System.in);
         int n = scanner.nextInt();
         int m = scanner.nextInt();
         int[][] grid = new int[n][m];
 ​
         for (int i = 0; i < n; i++) {
             for (int j = 0; j < m; j++) {
                 grid[i][j] = scanner.nextInt();
             }
         }
 ​
         // 步骤一:
         // 从左侧边,和右侧边 向中间遍历
         for (int i = 0; i < n; i++) {
             if (grid[i][0] == 1) dfs(grid, i, 0);
             if (grid[i][m - 1] == 1) dfs(grid, i, m - 1);
         }
 ​
         // 从上边和下边 向中间遍历
         for (int j = 0; j < m; j++) {
             if (grid[0][j] == 1) dfs(grid, 0, j);
             if (grid[n - 1][j] == 1) dfs(grid, n - 1, j);
         }
 ​
         // 步骤二、步骤三
         for (int i = 0; i < n; i++) {
             for (int j = 0; j < m; j++) {
                 if (grid[i][j] == 1) grid[i][j] = 0;
                 if (grid[i][j] == 2) grid[i][j] = 1;
             }
         }
 ​
         for (int i = 0; i < n; i++) {
             for (int j = 0; j < m; j++) {
                 System.out.print(grid[i][j] + " ");
             }
             System.out.println();
         }
         
         scanner.close();
     }
 }
 ​

水流问题

 //两个visited,如果firstborder[i][j]==1 && secondborder[i][j]==1则可以到达两个边界
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Scanner;
 ​
 public class Main {
     public static void main(String[] args) {
         Scanner sc = new Scanner(System.in);
         int m = sc.nextInt();
         int n = sc.nextInt();
         int[][] grid = new int[m][n];
         for (int i = 0; i < m; i++) {
             for (int j = 0; j < n; j++) {
                 grid[i][j] = sc.nextInt();
             }
         }
         int[][] firstborder = new int[m][n];
         int[][] secondborder = new int[m][n];
         for (int i = 0; i < m; i++) {
             dfs(grid, i,0, firstborder );
             dfs(grid, i,n - 1, secondborder );
         }
         for (int j = 0; j < n; j++) {
             dfs(grid, 0, j, firstborder );
             dfs(grid, m-1, j, secondborder );
         }
 // //        List<List<Integer>> res = new ArrayList<>();
 //         for (int i = 0; i < m; i++) {
 //             for (int j = 0; j < n; j++) {
 //                 if(firstborder[i][j]!=0 && secondborder[i][j]!=0) {
 // //                  res.add(Arrays.asList(i,j));
 //                     System.out.println(i + " " + j);
 //                 }
         // }
         // 当两个边界二维数组在某个位置都为true时,符合题目要求
         List<List<Integer>> res = new ArrayList<>();
         for (int i = 0; i < m; i++) {
             for (int j = 0; j < n; j++) {
                 if (firstborder[i][j]==1 && secondborder[i][j]==1) {
                     res.add(Arrays.asList(i, j));
                 }
             }
         }
 ​
         // 打印结果
         for (List<Integer> list : res) {
             for (int k = 0; k < list.size(); k++) {
                 if (k == 0) {
                     System.out.print(list.get(k) + " ");
                 } else {
                     System.out.print(list.get(k));
                 }
             }
             System.out.println();
         }
     }
 ​
     static int[][] dir = { {-1, 0}, {0, -1}, {1, 0}, {0, 1} };
     public static void dfs(int[][] grid, int x, int y, int[][] visited){
         if (visited[x][y] != 0) return;
         visited[x][y] = 1;
         for (int[] d : dir) {
             int nextX = x + d[0];
             int nextY = y + d[1];
             // 超过边界
             if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) continue;
             // 不符合条件,不继续遍历
             if (visited[nextX][nextY] == 1 || grid[nextX][nextY] < grid[x][y]) continue;//visited和grid
             dfs(grid, nextX, nextY, visited);
         }
     }
 }
 ​

建造最大岛屿

 //判断是不是全是陆地
 //判断水格子周围有没有其他编号的陆地块
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Scanner;
 import java.util.Set;
 ​
 public class Main{
     // 该方法采用 DFS
     // 定义全局变量
     // 记录每次每个岛屿的面积
     static int count;
     // 对每个岛屿进行标记
     static int mark;
     // 定义二维数组表示四个方位
     static int[][] dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
 ​
     // DFS 进行搜索,将每个岛屿标记为不同的数字
     public static void dfs(int[][] grid, int x, int y, boolean[][] visited) {
         // 当遇到边界,直接return
         if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length) return;
         // 遇到已经访问过的或者遇到海水,直接返回
         if (visited[x][y] || grid[x][y] == 0) return;
 ​
         visited[x][y] = true;
         count++;
         grid[x][y] = mark;
 ​
         // 继续向下层搜索
         dfs(grid, x, y + 1, visited);
         dfs(grid, x, y - 1, visited);
         dfs(grid, x + 1, y, visited);
         dfs(grid, x - 1, y, visited);
     }
 ​
     public static void main (String[] args) {
         // 接收输入
         Scanner sc = new Scanner(System.in);
         int m = sc.nextInt();
         int n = sc.nextInt();
 ​
         int[][] grid = new int[m][n];
         for (int i = 0; i < m; i++) {
             for (int j = 0; j < n; j++) {
                 grid[i][j] = sc.nextInt();
             }
         }
 ​
         // 初始化mark变量,从2开始(区别于0水,1岛屿)
         mark = 2;
 ​
         // 定义二位boolean数组记录该位置是否被访问
         boolean[][] visited = new boolean[m][n];
 ​
         // 定义一个HashMap,记录某片岛屿的标记号和面积
         HashMap<Integer, Integer> getSize = new HashMap<>();
 ​
         // 定义一个HashSet,用来判断某一位置水四周是否存在不同标记编号的岛屿
         Set<Integer> set = new HashSet<>();
 ​
         // 定义一个boolean变量,看看DFS之后,是否全是岛屿
         boolean isAllIsland = true;
 ​
         // 遍历二维数组进行DFS搜索,标记每片岛屿的编号,记录对应的面积
         for (int i = 0; i < m; i++) {
             for (int j = 0; j < n; j++) {
                 if (grid[i][j] == 0) isAllIsland = false;
                 if (grid[i][j] == 1) {
                     count = 0;
                     dfs(grid, i, j, visited);
                     getSize.put(mark, count);
                     mark++;
                 }
             }
         }
 ​
         int result = 0;
         if (isAllIsland) {
            System.out.println(m*n);
            return;
         }
 ​
         // 对标记完的grid继续遍历,判断每个水位置四周是否有岛屿,并记录下四周不同相邻岛屿面积之和
         // 每次计算完一个水位置周围可能存在的岛屿面积之和,更新下result变量
         for (int i = 0; i < m; i++) {
             for (int j = 0; j < n; j++) {
                 if (grid[i][j] == 0) {
                     set.clear();
                     // 当前水位置变更为岛屿,所以初始化为1
                     int curSize = 1;
 ​
                     for (int[] dir : dirs) {
                         int curRow = i + dir[0];
                         int curCol = j + dir[1];
 ​
                         if (curRow < 0 || curRow >= m || curCol < 0 || curCol >= n) continue;
                         int curMark = grid[curRow][curCol];
                         // 如果当前相邻的岛屿已经遍历过或者HashMap中不存在这个编号,继续搜索
                         if (set.contains(curMark) || !getSize.containsKey(curMark)) continue;
                         set.add(curMark);
                         curSize += getSize.get(curMark);
                     }
 ​
                     result = Math.max(result, curSize);
                 }
             }
         }
 ​
         // 打印结果
         System.out.println(result);
     }
 }
 ​
 ​

感谢大佬分享:

代码随想录算法训练营第五十二天|Day52 图论-CSDN博客


http://www.kler.cn/a/440919.html

相关文章:

  • BurpSuite抓包与HTTP基础
  • 《大数据时代“快刀”:Flink实时数据处理框架优势全解析》
  • android主题设置为..DarkActionBar.Bridge时自定义DatePicker选中日期颜色
  • 知识库管理如何推动企业数字化转型与创新发展的深层次探索
  • 主流的AEB标准有哪些?
  • 数据结构-Stack和栈
  • vue子组件在什么情况下会更新
  • 按键精灵苹果 iOS 脚本工具的基本编写方法
  • 【Prompt Engineering】5 文本转换
  • 3GPP协议解读_物理层系列(二)_RB SB SC什么关系?
  • 【代码随想录|动态规划02】
  • 【日期规则】EXCEl 自定义日期匹配规则,学习基础知识,自由匹配场景
  • vue+node+mysql8.0,详细步骤及报错解决方案
  • 【uni-app】微信小程序引入lime-echart并使用
  • 自动驾驶控制与规划——Project 2: 车辆横向控制
  • Python:跨文件实现字符串填充
  • 2024-2030全球与中国E-ink电子铭牌市场现状及未来发展趋势
  • 3D目标检测数据集及评价指标
  • 【前端】html学习记录
  • Nginx-rtmp-module 模块应用
  • css常用属性有哪些
  • 3D视觉[一]3D计算机视觉
  • 高防CDN 如何防止DDoS和CC攻击?
  • 【工具】使用 Gin 集成 pprof 进行性能调优
  • WebRTC服务质量(05)- 重传机制(02) NACK判断丢包
  • 基于MATLAB 的数字图像处理技术总结