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);}// 从上边和下边向中间遍历//上下边界贴边的岛屿设为0for (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变成1import 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和griddfs(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) {// 当遇到边界,直接returnif (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();// 当前水位置变更为岛屿,所以初始化为1int 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博客