当前位置:   article > 正文

【蓝桥杯3538】合并区域(bfs&java&模拟)_蓝桥杯java合并区域

蓝桥杯java合并区域

问题描述

输入输出

解题思路一(未通过)

题目的意思是给你两个n*n的矩阵,你需要将其以不同方式进行合并,并最终求得最大区域的面积。

初次尝试时,我想的是不需要实现合并,可以转化为左边最大区域+右边最大区域即为结果(如题目所给例图),当然也有可能是两区域中的某个“内陆”区域最大(如下图所示)

初次代码(未通过)

  1. import java.util.LinkedList;
  2. import java.util.Queue;
  3. import java.util.Scanner;
  4. class Pos {
  5. int x, y;
  6. public Pos(int x, int y) {
  7. this.x = x;
  8. this.y = y;
  9. }
  10. }
  11. public class Main {
  12. // 不临海也有可能是最大值
  13. static int innerMax = 0;
  14. public static void main(String[] args) {
  15. Scanner scan = new Scanner(System.in);
  16. int n = scan.nextInt();
  17. int[][] island1 = new int[n + 1][n + 1];
  18. int[][] island2 = new int[n + 1][n + 1];
  19. for (int i = 1; i <= n; i++) {
  20. for (int j = 1; j <= n; j++) {
  21. island1[i][j] = scan.nextInt();
  22. }
  23. }
  24. for (int i = 1; i <= n; i++) {
  25. for (int j = 1; j <= n; j++) {
  26. island2[i][j] = scan.nextInt();
  27. }
  28. }
  29. scan.close();
  30. int outerArea1 = bfsOuter(island1, n);
  31. int outerArea2 = bfsOuter(island2, n);
  32. if (outerArea1 + outerArea2 > innerMax) {
  33. System.out.println(outerArea1 + outerArea2);
  34. } else {
  35. System.out.println(innerMax);
  36. }
  37. }
  38. // bfs遍历获取临海区域的最大值
  39. public static int bfsOuter(int island[][], int n) {
  40. int outerMax = 0; //记录最大的临海区域面积
  41. boolean[][] visited = new boolean[n + 1][n + 1]; //记录是否访问过
  42. Queue<Pos> queue = new LinkedList<>(); //bfs队列
  43. int[][] dirs = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } }; //上、右、下、左四个方向
  44. for (int i = 1; i <= n; i++) {
  45. for (int j = 1; j <= n; j++) {
  46. if (visited[i][j] == false && island[i][j] == 1) {
  47. queue.offer(new Pos(i, j));
  48. visited[i][j] = true;
  49. int count = 1; //记录当前面积
  50. boolean outer = false; // 记录是否临海,不临海无法相连两个区域
  51. while (!queue.isEmpty()) {
  52. Pos pos = queue.poll();
  53. for (int[] dir : dirs) {
  54. int x = pos.x + dir[0];
  55. int y = pos.y + dir[1];
  56. if (x >= 1 && x <= n && y >= 1 && y <= n && island[x][y] == 1 && visited[x][y] == false) {
  57. visited[x][y] = true;
  58. queue.offer(new Pos(x, y));
  59. count++;
  60. // 若临海则更新outer的值
  61. if (x == 1 || x == n || y == 1 || y == n) {
  62. outer = true;
  63. }
  64. }
  65. }
  66. }
  67. if (outer) { //是否临海
  68. outerMax = Math.max(outerMax, count);
  69. } else {
  70. innerMax = Math.max(innerMax, count);
  71. }
  72. }
  73. }
  74. }
  75. return outerMax;
  76. }
  77. }

 只过了百分之十的数据,没有考虑到左边的区域将右边的两个区域连通起来的情况。

果然还是没法取巧,得老老实实合并区域(倒.jpg)

解题思路二

参考思路

将两个n*n大小的矩阵以不同方式合并后再用bfs/dfs求出最大面积即可。

可以通过边进行分类,4条边组合上4条边,总共有4*4=16种。

不过因为连接的边重叠的格子数不同,所以每种又会有2n-1个。

旋转90度的公式可以推导出来,可以看出原矩阵的[i][j]变为旋转90度后的矩阵的[j][n-i-1]。

至于矩阵合并的具体实现,可以用count来记录偏移值,从2n-1到1。

合并后用bfs求最大面积的方式大体同解题思路一,是很常规的解法。

蓝桥杯也有一道很相似的题——【蓝桥杯3513】岛屿个数(BFS&java)

AC代码

  1. import java.util.LinkedList;
  2. import java.util.Queue;
  3. import java.util.Scanner;
  4. //存储点的坐标
  5. class Pos {
  6. int x, y;
  7. public Pos(int x, int y) {
  8. this.x = x;
  9. this.y = y;
  10. }
  11. }
  12. public class Main {
  13. public static void main(String[] args) {
  14. Scanner scan = new Scanner(System.in);
  15. int n = scan.nextInt();
  16. // 建立并读入两个矩阵
  17. int[][] island1 = new int[n][n];
  18. int[][] island2 = new int[n][n];
  19. for (int i = 0; i < n; i++) {
  20. for (int j = 0; j < n; j++) {
  21. island1[i][j] = scan.nextInt();
  22. }
  23. }
  24. for (int i = 0; i < n; i++) {
  25. for (int j = 0; j < n; j++) {
  26. island2[i][j] = scan.nextInt();
  27. }
  28. }
  29. scan.close();
  30. // 持续旋转90度得到两个矩阵分别旋转90、180、270度的矩阵
  31. int[][] island1_90 = rotate90(island1);
  32. int[][] island1_180 = rotate90(island1_90);
  33. int[][] island1_270 = rotate90(island1_180);
  34. int[][] island2_90 = rotate90(island2);
  35. int[][] island2_180 = rotate90(island2_90);
  36. int[][] island2_270 = rotate90(island2_180);
  37. // 存入三维数组方便调用
  38. int[][][] islands1 = { island1, island1_90, island1_180, island1_270 };
  39. int[][][] islands2 = { island2, island2_90, island2_180, island2_270 };
  40. // count变量记录偏移值
  41. int count = 2 * n - 1, max = 0;
  42. while (count > 0) {
  43. // 根据边分为4*4=16种,每种再根据偏移变量count进行合并
  44. for (int i = 0; i < 4; i++) {
  45. for (int j = 0; j < 4; j++) {
  46. // 根据count偏移值合并两个矩阵,并用bfs求得合并后的最大面积,若最大面积大于当前最大面积则更新
  47. max = Math.max(max, bfsMaxArea(mergeIslands(islands1[i], islands2[j], count), 2 * n));
  48. }
  49. }
  50. count--; // 要在while循环的最后才能减去一,不然会影响运算
  51. }
  52. System.out.println(max);
  53. }
  54. // 顺时针旋转矩阵90度后返回
  55. public static int[][] rotate90(int[][] map) {
  56. int n = map.length;
  57. int[][] map_90 = new int[n][n];
  58. for (int i = 0; i < n; i++) {
  59. for (int j = 0; j < n; j++) {
  60. map_90[j][n - i - 1] = map[i][j];
  61. }
  62. }
  63. return map_90;
  64. }
  65. // 合并两个数组并返回
  66. public static int[][] mergeIslands(int[][] map1, int[][] map2, int count) {
  67. int n = map1.length;
  68. // 合并后的数组横坐标最大值为2n-1(因为至少一行相接),列坐标最大值为2n,但是为了bfs方便都设置为2n
  69. int[][] map = new int[2 * n][2 * n];
  70. // 若count>=n
  71. if (count >= n) {
  72. // 将map1放在map的左上角
  73. for (int i = 0; i < n; i++) {
  74. for (int j = 0; j < n; j++) {
  75. map[i][j] = map1[i][j];
  76. }
  77. }
  78. // 再根据map1的位置和偏移量count确定map2的位置
  79. for (int i = count - n; i < count; i++) {
  80. for (int j = n; j <= 2 * n - 1; j++) {
  81. map[i][j] = map2[i - (count - n)][j - n];
  82. }
  83. }
  84. } else {
  85. // 否则将map1放在左下角
  86. for (int i = n - 1; i < 2 * n - 1; i++) {
  87. for (int j = 0; j < n; j++) {
  88. map[i][j] = map1[i - (n - 1)][j];
  89. }
  90. }
  91. // 再根据map1的位置和偏移量count确定map2的位置
  92. for (int i = count - 1; i < count - 1 + n; i++) {
  93. for (int j = n; j <= 2 * n - 1; j++) {
  94. map[i][j] = map2[i - (count - 1)][j - n];
  95. }
  96. }
  97. }
  98. // 输出每次合并后的矩阵查验
  99. // System.out.println();
  100. // for (int i = 0; i < 2 * n - 1; i++) {
  101. // for (int j = 0; j <= 2 * n - 1; j++) {
  102. // System.out.print(map[i][j] + " ");
  103. // }
  104. // System.out.println();
  105. // }
  106. return map;
  107. }
  108. // bfs遍历获取面积最大值
  109. public static int bfsMaxArea(int island[][], int n) {
  110. int areaMax = 0; // 记录最大面积
  111. boolean[][] visited = new boolean[n][n]; // 记录是否访问过
  112. Queue<Pos> queue = new LinkedList<>(); // bfs队列
  113. int[][] dirs = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } }; // 上、右、下、左四个方向
  114. for (int i = 0; i < n; i++) {
  115. for (int j = 0; j < n; j++) {
  116. if (visited[i][j] == false && island[i][j] == 1) {
  117. queue.offer(new Pos(i, j));
  118. visited[i][j] = true;
  119. int area = 1; // 记录当前面积
  120. while (!queue.isEmpty()) {
  121. Pos pos = queue.poll();
  122. for (int[] dir : dirs) {
  123. // 移动后的坐标值
  124. int x = pos.x + dir[0];
  125. int y = pos.y + dir[1];
  126. // 未访问过且为陆地且在区域内
  127. if (x >= 0 && x < n && y >= 0 && y < n && island[x][y] == 1 && visited[x][y] == false) {
  128. visited[x][y] = true;
  129. queue.offer(new Pos(x, y));
  130. area++;
  131. }
  132. }
  133. }
  134. // 更新面积最大值
  135. areaMax = Math.max(areaMax, area);
  136. }
  137. }
  138. }
  139. return areaMax;
  140. }
  141. }

评价

这道题的难度其实不算很大,就是合并区域那一块有点麻烦,需要计算很多。思路理顺后很好解决。

(by 归忆)

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

闽ICP备14008679号