当前位置:   article > 正文

代码随想录Day66(图论Part03)

代码随想录Day66(图论Part03)

101.孤岛的总面积

题目:101. 孤岛的总面积 (kamacoder.com)

思路:无

答案
  1. import java.util.Scanner;
  2. class Main {
  3. private static int N, M;
  4. private static int[][] grid;
  5. private static boolean[][] visited;
  6. private static boolean touchesEdge;
  7. public static void main(String[] args) {
  8. Scanner scanner = new Scanner(System.in);
  9. N = scanner.nextInt();
  10. M = scanner.nextInt();
  11. grid = new int[N][M];
  12. visited = new boolean[N][M];
  13. for (int i = 0; i < N; i++) {
  14. for (int j = 0; j < M; j++) {
  15. grid[i][j] = scanner.nextInt();
  16. }
  17. }
  18. int totalIslandArea = 0;
  19. for (int i = 0; i < N; i++) {
  20. for (int j = 0; j < M; j++) {
  21. if (grid[i][j] == 1 && !visited[i][j]) {
  22. touchesEdge = false;
  23. int islandArea = dfs(i, j);
  24. if (!touchesEdge) {
  25. totalIslandArea += islandArea;
  26. }
  27. }
  28. }
  29. }
  30. System.out.println(totalIslandArea);
  31. }
  32. private static int dfs(int x, int y) {
  33. if (x < 0 || x >= N || y < 0 || y >= M) {
  34. return 0;
  35. }
  36. if (grid[x][y] == 0 || visited[x][y]) {
  37. return 0;
  38. }
  39. if (x == 0 || x == N - 1 || y == 0 || y == M - 1) {
  40. touchesEdge = true;
  41. }
  42. visited[x][y] = true;
  43. int area = 1;
  44. area += dfs(x + 1, y);
  45. area += dfs(x - 1, y);
  46. area += dfs(x, y + 1);
  47. area += dfs(x, y - 1);
  48. return area;
  49. }
  50. }
小结

在dfs里面需要判断岛屿时候接触边缘

102.沉没孤岛

题目:102. 沉没孤岛 (kamacoder.com)

思路:判断周围也没有岛屿,上下左右都没有,那就将当前位置变为0

尝试(标题4)
  1. import java.util.Scanner;
  2. class Main{
  3. public static int m;
  4. public static int n;
  5. public static int[][] grid;
  6. public static boolean[][] visited;
  7. public static void main(String[] args){
  8. Scanner scanner = new Scanner(System.in);
  9. n = scanner.nextInt();
  10. m = scanner.nextInt();
  11. grid = new int[n][m];
  12. visited = new boolean[n][m];
  13. for(int i=0; i<n; i++){
  14. for(int j=0; j<m; j++){
  15. grid[i][j] = scanner.nextInt();
  16. }
  17. }
  18. for (int i = 0; i < n; i++) {
  19. for (int j = 0; j < m; j++) {
  20. if (grid[i][j] == 1 && !visited[i][j]) {
  21. int area = dfs(i, j);
  22. if(area == 1) grid[i][j] = 0;
  23. }
  24. }
  25. }
  26. for (int i = 0; i < n; i++) {
  27. for (int j = 0; j < m; j++) {
  28. System.out.print(grid[i][j]+" ");
  29. }
  30. System.out.println();
  31. }
  32. }
  33. private static int dfs(int i, int j) {
  34. if (i < 0 || i >= n || j < 0 || j >= m || grid[i][j] == 0 || visited[i][j]) {
  35. return 0;
  36. }
  37. visited[i][j] = true;
  38. int area = 1; // 当前格子的面积为1
  39. // 上
  40. area += dfs(i - 1, j);
  41. // 下
  42. area += dfs(i + 1, j);
  43. // 左
  44. area += dfs(i, j - 1);
  45. // 右
  46. area += dfs(i, j + 1);
  47. return area;
  48. }
  49. }
答案
  1. import java.util.Scanner;
  2. class Main {
  3. public static void main(String[] args) {
  4. Scanner scanner = new Scanner(System.in);
  5. // 读取矩阵的行数和列数
  6. int N = scanner.nextInt();
  7. int M = scanner.nextInt();
  8. int[][] grid = new int[N][M];
  9. // 读取矩阵
  10. for (int i = 0; i < N; i++) {
  11. for (int j = 0; j < M; j++) {
  12. grid[i][j] = scanner.nextInt();
  13. }
  14. }
  15. // 从边缘开始标记所有与边缘相连的陆地
  16. for (int i = 0; i < N; i++) {
  17. if (grid[i][0] == 1) {
  18. dfs(grid, i, 0, N, M);
  19. }
  20. if (grid[i][M - 1] == 1) {
  21. dfs(grid, i, M - 1, N, M);
  22. }
  23. }
  24. for (int j = 0; j < M; j++) {
  25. if (grid[0][j] == 1) {
  26. dfs(grid, 0, j, N, M);
  27. }
  28. if (grid[N - 1][j] == 1) {
  29. dfs(grid, N - 1, j, N, M);
  30. }
  31. }
  32. // 将所有未标记的陆地(孤岛)沉没
  33. for (int i = 0; i < N; i++) {
  34. for (int j = 0; j < M; j++) {
  35. if (grid[i][j] == 1) {
  36. grid[i][j] = 0;
  37. } else if (grid[i][j] == 2) {
  38. grid[i][j] = 1;
  39. }
  40. }
  41. }
  42. // 输出结果矩阵
  43. for (int i = 0; i < N; i++) {
  44. for (int j = 0; j < M; j++) {
  45. System.out.print(grid[i][j] + " ");
  46. }
  47. System.out.println();
  48. }
  49. scanner.close();
  50. }
  51. // 深度优先搜索(DFS)函数
  52. private static void dfs(int[][] grid, int x, int y, int N, int M) {
  53. if (x < 0 || x >= N || y < 0 || y >= M || grid[x][y] != 1) {
  54. return;
  55. }
  56. grid[x][y] = 2; // 标记为非孤岛
  57. dfs(grid, x + 1, y, N, M);
  58. dfs(grid, x - 1, y, N, M);
  59. dfs(grid, x, y + 1, N, M);
  60. dfs(grid, x, y - 1, N, M);
  61. }
  62. }
小结

先标记所有非孤岛,再沉没所有孤岛,再撤销所有非孤岛标记

103.水流问题

题目:103. 水流问题 (kamacoder.com)

思路:我需要找到最大的数字,然后再用dfs搜索?以每一个格子为中心,画一个十字,只要有朝向第一组边界和朝向第二组边界的递减数组即可,写一个函数,计算水流能否到达第一组边界,另一个函数计算水流能否到达第二组边界,两个函数返回均为true时,记录该坐标

尝试(超时)
  1. import java.util.Scanner;
  2. import java.util.ArrayList;
  3. class Main{
  4. public static int N;
  5. public static int M;
  6. public static int[][] grid;
  7. public static void main(String[] args){
  8. Scanner scanner = new Scanner(System.in);
  9. N = scanner.nextInt();
  10. M = scanner.nextInt();
  11. grid = new int[N][M];
  12. ArrayList<int[]> dynamicArray = new ArrayList<>();
  13. for(int i=0; i<N; i++){
  14. for(int j=0; j<M; j++){
  15. grid[i][j] = scanner.nextInt();
  16. }
  17. }
  18. for(int i=0; i<N; i++){
  19. for(int j=0; j<M; j++){
  20. if(firstBoundary(i,j) && secondBoundary(i,j)){
  21. dynamicArray.add(new int[]{i,j});
  22. }
  23. }
  24. }
  25. // 输出动态数组中的内容
  26. for (int[] array : dynamicArray) {
  27. System.out.println(array[0] + " " + array[1]);
  28. }
  29. }
  30. public static boolean firstBoundary(int i,int j){
  31. boolean up = true;
  32. boolean left = true;
  33. for(int k=i; k>0; k--){
  34. if(grid[k][j]>grid[i][j]) up = false;
  35. }
  36. for(int k=j; k>0; k--){
  37. if(grid[i][k]>grid[i][j]) left = false;
  38. }
  39. return up|| left;
  40. }
  41. public static boolean secondBoundary(int i,int j){
  42. boolean down = true;
  43. boolean right = true;
  44. for(int k=i; k<N; k++){
  45. if(grid[k][j]>grid[i][j]) down = false;
  46. }
  47. for(int k=j; k<M; k++){
  48. if(grid[i][k]>grid[i][j]) right = false;
  49. }
  50. return down||right;
  51. }
  52. }
答案
  1. import java.util.ArrayList;
  2. import java.util.Scanner;
  3. class Main {
  4. public static int N;
  5. public static int M;
  6. public static int[][] grid;
  7. public static boolean[][] canReachFirstBoundary;
  8. public static boolean[][] canReachSecondBoundary;
  9. public static void main(String[] args) {
  10. Scanner scanner = new Scanner(System.in);
  11. N = scanner.nextInt();
  12. M = scanner.nextInt();
  13. grid = new int[N][M];
  14. canReachFirstBoundary = new boolean[N][M];
  15. canReachSecondBoundary = new boolean[N][M];
  16. for (int i = 0; i < N; i++) {
  17. for (int j = 0; j < M; j++) {
  18. grid[i][j] = scanner.nextInt();
  19. }
  20. }
  21. // 从第一组边界开始反向DFS
  22. for (int i = 0; i < N; i++) {
  23. dfs(i, 0, canReachFirstBoundary);
  24. dfs(i, M - 1, canReachSecondBoundary);
  25. }
  26. for (int j = 0; j < M; j++) {
  27. dfs(0, j, canReachFirstBoundary);
  28. dfs(N - 1, j, canReachSecondBoundary);
  29. }
  30. // 找出既能到达第一组边界又能到达第二组边界的单元格
  31. ArrayList<int[]> result = new ArrayList<>();
  32. for (int i = 0; i < N; i++) {
  33. for (int j = 0; j < M; j++) {
  34. if (canReachFirstBoundary[i][j] && canReachSecondBoundary[i][j]) {
  35. result.add(new int[]{i, j});
  36. }
  37. }
  38. }
  39. // 输出结果
  40. for (int[] cell : result) {
  41. System.out.println(cell[0] + " " + cell[1]);
  42. }
  43. }
  44. // 深度优先搜索(DFS)函数
  45. private static void dfs(int x, int y, boolean[][] canReach) {
  46. if (canReach[x][y]) {
  47. return;
  48. }
  49. canReach[x][y] = true;
  50. int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
  51. for (int[] direction : directions) {
  52. int newX = x + direction[0];
  53. int newY = y + direction[1];
  54. if (newX >= 0 && newX < N && newY >= 0 && newY < M && grid[newX][newY] >= grid[x][y]) {
  55. dfs(newX, newY, canReach);
  56. }
  57. }
  58. }
  59. }
小结

反向dfs效率更高

104.建造最大岛屿

题目:104. 建造最大岛屿 (kamacoder.com)

思路:感觉肯定是要找到最大的岛屿,再去连接,或者是第二大的,又或者是岛屿从大到小,都试一遍,逐个将岛屿的某个边缘变为陆地

这个1 肯定是出现在岛屿的边缘,或许我可以先遍历一遍,找到所有的边缘,

尝试(写不出来)
  1. import java.util.Scanner;
  2. class Main{
  3. public static int N;
  4. public static int M;
  5. public static int[][] grid;
  6. public static boolean[][] visited;
  7. public static boolean flag;
  8. public static void main(String[] args){
  9. Scanner scan = new Scanner(System.in);
  10. N = scan.nextInt();
  11. M = scan.nextInt();
  12. grid = new int[N][M];
  13. for(int i=0; i<N; i++){
  14. for(int j=0; j<M; j++){
  15. grid[i][j] = scan.nextInt();
  16. }
  17. }
  18. // 遍历grid,找到所有的边缘,单元格每与一个陆地接触,就加1
  19. // 初始值为2,为了区分岛屿的1
  20. for(int i=0; i<N; i++){
  21. for(int j=0; j<M; j++){
  22. grid[i][j] = scan.nextInt();
  23. }
  24. }
  25. }
  26. public static void dfs(int i, int j){
  27. if(i<0 || i>=N || j<0 || j>=M){
  28. return;
  29. }
  30. visited[i][j] = true;
  31. if(grid[i][j]==1) flag = true;
  32. if(flag){
  33. if(grid[i][j]==0){
  34. grid[i][j] =2;
  35. }else{
  36. grid[i][j]+=1;
  37. }
  38. }
  39. dfs(i-1,j);
  40. dfs(i+1,j);
  41. dfs(i,j-1);
  42. dfs(i,j+1);
  43. }
  44. }
答案(卡码网上别人的,看不懂)
  1. import java.util.Arrays;
  2. import java.util.Map;
  3. import java.util.Scanner;
  4. // 逆向思维
  5. public class Main {
  6. static int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}};
  7. static int ans = 0, area = 1;
  8. static boolean[][] visited;
  9. public static void main(String[] args) {
  10. Scanner sc = new Scanner(System.in);
  11. int n = sc.nextInt(); // row
  12. int m = sc.nextInt(); // col
  13. int[][] graph = new int[n][m];
  14. for (int i = 0; i < n; i++) {
  15. for (int j = 0; j < m; j++) {
  16. graph[i][j] = sc.nextInt();
  17. }
  18. }
  19. boolean flag = false;
  20. // 遍历
  21. for (int i = 0; i < n; i++) {
  22. for (int j = 0; j < m; j++) {
  23. area = 1;
  24. visited = new boolean[n][m];
  25. if (graph[i][j] == 0){
  26. dfs(i, j, graph, n, m);
  27. flag = true;
  28. }
  29. }
  30. }
  31. System.out.println(flag ? ans : n * m);
  32. }
  33. private static void dfs(int row, int col, int[][] graph, int n, int m) {
  34. ans = Math.max(ans, area);
  35. visited[row][col] = true;
  36. for (int[] dir : dirs) {
  37. int newX = dir[0] + row;
  38. int newY = dir[1] + col;
  39. if(newX >= 0 && newX < n && newY >= 0 && newY < m && graph[newX][newY] == 1 && !visited[newX][newY]){
  40. area++;
  41. dfs(newX,newY,graph,n,m);
  42. }
  43. }
  44. }
  45. }
答案(仿照代码随想录中C++的逻辑,运行错误)
  1. import java.util.*;
  2. public class Main {
  3. static int n, m;
  4. static int count;
  5. static int[][] dir = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; // 四个方向
  6. public static void main(String[] args) {
  7. Scanner scanner = new Scanner(System.in);
  8. n = scanner.nextInt();
  9. m = scanner.nextInt();
  10. int[][] grid = new int[n][m];
  11. for (int i = 0; i < n; i++) {
  12. for (int j = 0; j < m; j++) {
  13. grid[i][j] = scanner.nextInt();
  14. }
  15. }
  16. boolean[][] visited = new boolean[n][m]; // 标记访问过的点,初始化为false
  17. Map<Integer, Integer> gridNum = new HashMap<>();
  18. int mark = 2; // 记录每个岛屿的编号
  19. boolean isAllGrid = true; // 标记是否整个地图都是陆地
  20. // 计算每个岛屿的面积并标记
  21. for (int i = 0; i < n; i++) {
  22. for (int j = 0; j < m; j++) {
  23. if (grid[i][j] == 0) isAllGrid = false;
  24. if (!visited[i][j] && grid[i][j] == 1) {
  25. count = 0;
  26. dfs(grid, visited, i, j, mark); // 将与其链接的陆地都标记上 true
  27. gridNum.put(mark, count); // 记录每一个岛屿的面积
  28. mark++; // 记录下一个岛屿编号
  29. }
  30. }
  31. }
  32. if (isAllGrid) {
  33. System.out.println(n * m); // 如果都是陆地,返回全面积
  34. return; // 结束程序
  35. }
  36. // 以下逻辑是根据添加陆地的位置,计算周边岛屿面积之和
  37. int result = 0; // 记录最后结果
  38. Set<Integer> visitedGrid = new HashSet<>(); // 标记访问过的岛屿
  39. for (int i = 0; i < n; i++) {
  40. for (int j = 0; j < m; j++) {
  41. count = 1; // 记录连接之后的岛屿数量
  42. visitedGrid.clear(); // 每次使用时,清空
  43. if (grid[i][j] == 0) {
  44. for (int k = 0; k < 4; k++) {
  45. int neari = i + dir[k][0]; // 计算相邻坐标
  46. int nearj = j + dir[k][1];
  47. if (neari < 0 || nearj < 0 || neari >= n || nearj >= m) continue;
  48. if (visitedGrid.contains(grid[neari][nearj])) continue; // 添加过的岛屿不要重复添加
  49. // 把相邻四面的岛屿数量加起来
  50. count += gridNum.get(grid[neari][nearj]);
  51. visitedGrid.add(grid[neari][nearj]); // 标记该岛屿已经添加过
  52. }
  53. }
  54. result = Math.max(result, count);
  55. }
  56. }
  57. System.out.println(result);
  58. }
  59. // 深度优先搜索函数
  60. private static void dfs(int[][] grid, boolean[][] visited, int x, int y, int mark) {
  61. if (visited[x][y] || grid[x][y] == 0) return;
  62. visited[x][y] = true; // 标记访问过
  63. grid[x][y] = mark; // 给陆地标记新标签
  64. count++;
  65. for (int i = 0; i < 4; i++) {
  66. int nextx = x + dir[i][0];
  67. int nexty = y + dir[i][1];
  68. if(nextx <0 || nextx >=n || nexty<0 || nexty >=m) continue;
  69. dfs(grid, visited, nextx, nexty, mark);
  70. }
  71. }
  72. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/804918
推荐阅读
相关标签
  

闽ICP备14008679号