【问题标题】:Unit Area of largest region of 1's1的最大区域的单位面积
【发布时间】:2020-06-18 19:22:53
【问题描述】:

考虑一个有 N 行 M 列的矩阵,其中每个单元格包含“0”或“1”,任何包含 1 的单元格都称为填充单元格。如果两个单元在水平、垂直或对角线上彼此相邻,则称它们是连接的。如果一个或多个填充单元相连,它们就形成一个区域。任务是找到最大区域的单位面积。

这是我的代码:

class GFG {
    static int max;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        for (int t = 0; t < T; t++) {
            max = 1;
            int R = sc.nextInt();
            int C = sc.nextInt();
            int[][] M = new int[R][C];
            for (int i = 0; i < R; i++) {
                for (int j = 0; j < C; j++) {
                    M[i][j] = sc.nextInt();
                }
            }
            printMatrix(M, R, C);
            boolean[][] visited = new boolean[R][C];
            for (int i = 0; i < R; i++) {
                for (int j = 0; j < C; j++) {
                    int L = 1;
                    if (M[i][j] == 1 && !visited[i][j])
                        markVisited(M, visited, i, j, R, C, L);
                }
            }
            System.out.println(max);
        }
    }

    private static void printMatrix(int[][] M, int R, int C) {
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                System.out.print(M[i][j] + " ");
            }
            System.out.println();
        }

    }

    public static boolean isSafe(int[][] M, boolean[][] visited, int i, int j, int R, int C) {
        return ((i >= 0 && i < R) && (j >= 0 && j < C) && (M[i][j] == 1 && (!visited[i][j])));
    }

    public static void markVisited(int[][] M, boolean[][] visited, int x, int y, int R, int C, int L) {
        // int[] x_pos = {1 , 1, 1, 0, 0, -1, -1, -1};
        // int[] y_pos = {-1, 0, 1, -1, 1, -1, 0, 1};
        //commenting the arrays, as selecting one of the above and below combinations, result in different outputs
        int[] x_pos = { -1, -1, -1, 0, 0, 1, 1, 1 };
        int[] y_pos = { -1, 0, 1, -1, 1, -1, 0, 1 };

        visited[x][y] = true;
        for (int k = 0; k < 8; k++) {
            if (isSafe(M, visited, x + x_pos[k], y + y_pos[k], R, C)) {
                L++;
                max = Math.max(L, max);
                markVisited(M, visited, x + x_pos[k], y + y_pos[k], R, C, L);
            }
        }

    }
}

代码不适用于下面提到的测试用例:
1
4 7
1 1 1 1 0 0 1 1 0 1 0 1 1 0 0 0 0 0 1 0 1 1 0 0 0 1 1 1
输出为 13,预期为 14。
有趣的是,如果我将 markVisited 方法中的 x_pos 和 y_pos(在代码中注释)更改为

int[] x_pos = {1 , 1, 1, 0, 0, -1, -1, -1};  
int[] y_pos = {-1, 0, 1, -1, 1, -1, 0, 1};

输出为 14。我不明白当 x_pos 和 y_pos 组合相同时输出如何变化。
它也发生在其他测试用例中。我评论了 x_pos[] 和 y_pos[]。
请提出问题所在。

【问题讨论】:

    标签: java algorithm graph depth-first-search breadth-first-search


    【解决方案1】:

    所以,您的问题是递归累积 L 的方式。这是您的输入数组:

    1 1 1 1 0 0 1

    1 0 1 0 1 1 0

    0 0 0 0 1 0 1

    1 0 0 0 1 1 1

    仅作为示例。如果你已经积累的路径被分成了两个不同的路径(让我们拿起你输入的前 3 行以便更好地理解)

    1 1 1 1 0 0 1

    1 0 1 0 1 1 0

    0 0 0 0 1 0 1

    在位置 (1, 5),您可以转到右上角的 1 或右下角的 1(您的路径一分为二),您将当前的 L 传递给其中的每一个,并且然后,这些路径中的每一个都在自己累积 L,而不是累积全局 L,该全局 L 旨在累积所有找到的 1,这些 1 属于主路径,其根是您找到的第一个 1。

    您的解决方法非常简单,只需将 L 移到变量的顶部,如下所示:

    static int max;
    static int L;
    

    然后,不要通过您的方法传递 L,而是在每次启动新根 1 时重新设置它的值:

    if (M[i][j] == 1 && !visited[i][j]) {
        L = 1;
        markVisited(M, visited, i, j, R, C);
    }
    

    最后,在你的 markVisited 中,做同样的事情,只是在你的方法结束时去掉那个 L 参数,因为你将使用全局参数:

    max = Math.max(++L, max);
    

    希望对您有所帮助,如果不清楚,请告诉我,以便我在需要时添加更多详细信息^-^

    值得一提的是,如果您更改变量,您的代码运行良好这一事实是巧合,因为这种行为取决于您在迭代中通过 1 的方式。根据您首先选择的 1,您可能会陷入这种情况,也可能不会,因此更改它们不是解决方案。

    【讨论】:

      【解决方案2】:

      问题在于您累积已访问单元格计数的方式。

      首先,您需要将外部循环更改为:

      int max = 0;          
      for (int i = 0; i < R; i++) {
          for (int j = 0; j < C; j++) {
              if (M[i][j] == 1 && !visited[i][j])
                max = Math.max(max, markVisited(M, visited, i, j, R, C));
          }
      }
      System.out.println(max);
      

      那么您的markVisited 方法应该返回访问的单元格的计数,因此将签名更改为:

      public static int markVisited(int[][] M, boolean[][] visited, int x, int y, int R, int C) 
      

      最后,您需要在递归到单元格的邻居时累积计数:

      int L = 1;
      for (int k = 0; k < 8; k++) {
          if (isSafe(M, visited, x + x_pos[k], y + y_pos[k], R, C)) {           
              L += markVisited(M, visited, x + x_pos[k], y + y_pos[k], R, C);
          }
      }
      return L;
      

      通过这些更改,无论您访问邻居的顺序如何,您都可以获得所需的输出:

      1 1 1 1 0 0 1 
      1 0 1 0 1 1 0 
      0 0 0 0 1 0 1 
      1 0 0 0 1 1 1 
      14
      

      【讨论】:

        猜你喜欢
        • 2013-12-31
        • 1970-01-01
        • 1970-01-01
        • 2012-07-17
        • 1970-01-01
        • 1970-01-01
        • 2021-11-07
        • 2013-09-20
        • 2012-03-05
        相关资源
        最近更新 更多