Java 用全部素数计算子矩阵

Java 用全部素数计算子矩阵,java,algorithm,matrix,dynamic-programming,Java,Algorithm,Matrix,Dynamic Programming,我得到了一个NxN矩阵。如果子矩阵满足以下条件,则认为它是特殊的: 它的形状一定是正方形的 所有数字都必须是素数 我必须计算满足以下条件的给定矩阵的子矩阵的总数 例如,让示例输入为=> 3 3 5 6 8 3 2 3 5 2 样本输出:8 说明: 1x1:有7个素数,每个1x1矩阵包含1个素数 2x2:只有右下角的子矩阵包含所有素数 3x3:没有3x3矩阵满足这些标准 最后的答案是(7+1+0)=8 我最近在一次采访中遇到了这个问题。我可以想出一个暴力解决方案。解决这个问题的最好办法是什么

我得到了一个NxN矩阵。如果子矩阵满足以下条件,则认为它是特殊的:

  • 它的形状一定是正方形的
  • 所有数字都必须是素数
  • 我必须计算满足以下条件的给定矩阵的子矩阵的总数

    例如,让示例输入为=>

    3
    3 5 6
    8 3 2
    3 5 2
    
    样本输出:8

    说明:

    • 1x1:有7个素数,每个1x1矩阵包含1个素数
    • 2x2:只有右下角的子矩阵包含所有素数
    • 3x3:没有3x3矩阵满足这些标准
    最后的答案是(7+1+0)=8

    我最近在一次采访中遇到了这个问题。我可以想出一个暴力解决方案。解决这个问题的最好办法是什么

    [更新] 我已放弃了解决这个问题的努力

    class TestClass 
    {
        public static boolean isPrime(int n)
        {
            if(n<2)
                return false;
            for(int i=2;i<=Math.sqrt(n);i++)
            {
                if(n%i==0)
                    return false;
            }
            return true;
        }
        public static boolean scan_matrix(boolean a[][], int start_i, int start_j, int n)
        {
            for(int i=start_i;i<start_i+n;i++)
            {
                for(int j=start_j;j<start_j+n;j++)
                {
                    if(!a[i][j])
                        return false;
                }
            }
            return true;
        }
        public static int count_valid_matrix(boolean a[][], int n, int N)
        {
            int result = 0;
            for(int start_i=0;start_i<=N-n;start_i++)
            {
                for(int start_j=0;start_j<=N-n;start_j++)
                {
                    if(scan_matrix(a, start_i, start_j, n))
                        result += 1;
                }
            }
            return result;
        }
    
        public static void main(String args[]) throws Exception
        {
            Scanner s = new Scanner(System.in);
            int N = s.nextInt();
            boolean a[][] = new boolean[N][N];
            int result = 0;
            for(int i=0;i<N; i++)
            {
                for(int j=0;j<N;j++)
                {
                    int num = s.nextInt();
                    a[i][j] = isPrime(num);
                    if(a[i][j])
                        result += 1;
                }
            }
            int n = 2;
            while(n<N)
            {
                result += count_valid_matrix(a, n, N);
                n++;
            }
            System.out.println(result);
        }
    }
    
    class测试类
    {
    公共静态布尔iPrime(int n)
    {
    
    如果(n这里是一个可能公式的一部分。让
    是特殊的(I,J,W)
    表示矩阵单元
    m(I,J)
    是否是宽度有效平方的右下角
    W
    。然后:

    是特别的(I,J,1)->
    is_素数(m(I,J));
    是特别的(I,J,W)->
    (I>=W-1,假设I从0开始
    (J>=W-1,假设J从0开始
    (I,J,W-1)和
    是特殊的(I-1,J,W-1)和
    _是特殊的(I,J-1,W-1)和
    是特别的(I-1,J-1,W-1))。
    
    Idea 首先,将(你做的)矩阵转换成0/1矩阵, 非素数用
    0
    ,素数用
    1

    现在,你有一个
    1
    s的“曲面”。你能在这个曲面上放多少个正方形? 想想看:如果你有一个
    3*3
    平方的
    1
    s从
    (0,0)
    开始,那么你已经 知道方块
    (1,0)-(2,1)
    (0,1)-(1,2)
    (1,1)-(2,2)
    1
    组成,因此您不必再次检查这些方块。 因此,您将查找从
    (1,0)
    (0,1)
    (1,1)
    开始的
    1
    平方,前提是它们大于
    2*2
    。 想象一下,从
    (1,0)
    开始的最大正方形的大小为
    3*3
    ,但另外两个正方形的大小为
    2*2
    。 您可以忽略后者(它们不会添加任何新内容),但必须添加新的
    3*3
    square并删除与前一个重叠的曲面

    这可以概括如下:

    • 将从
      (0,0)
      开始的最大正方形大小存储在矩阵
      M
    • N
      =大小为
      M[0,0]
    • 对于每个
      (r,c)
      ,从左到右,从上到下:
      • M
        获取从
        (r-1,c)
        (r,c-1)
        (r-1,c-1)
        开始的最大正方形大小,比如说
        K
        • 计算从
          (r,c)
          开始的最大正方形大小(从
          K-1开始)
        • 如果
          M[r,c]
          =
          K-1
          ,则不执行任何操作
        • 如果
          M[r,c]
          K-1
          ,则更新
          N
          N
          +=一个正方形大小的子正方形数
          M[r,c]
          -子正方形数 正方形大小的子正方形
          K-1
    诀窍是“计算从
    (r,c)
    (从
    K-1开始)
    )开始的最大正方形大小”将省去大量比较

    伪代码(类似Python) 首先,请注意,大小为
    k
    的正方形包含大小为
    k^2
    的正方形
    1
    (k-1)^2
    的正方形 大小
    2
    ,…,
    1
    大小的平方
    k
    。这是一个众所周知的总数(我从维基百科获得了结果!):

    计算凝视
    (r,c)
    1
    s的最大平方的大小并不困难。我添加了一个从
    K开始的开始:

    def largest_square_size(m, r, c, K):
        k = K
        while k<n:
            # check the border
            for l in 0..k:
                if m[r+k, c+l] == 0 or m[r+l, c+k] == 0: # consider the left and bottom borders
                    break while
            if m[r+k, c+k] == 0 # don't forget the corner
                break while
            k += 1
        return k
    
    免责声明:我没有测试这一点,可能有边缘的情况,但我认为这是正确的


    它显然是次优的,因为某些位置可能会被多次检查,但它应该表现良好。

    你能展示你的尝试吗?看起来是动态规划算法的一个很好的候选者。2x2矩阵实际上是4个彼此相邻的1x1矩阵,这意味着如果你解决较小矩阵的问题,并保存相关信息,应建立。提示1:每个2x2子矩阵包含四个1x1子矩阵。每个3x3子矩阵包含四个2x2子矩阵。提示2:
    def largest_square_size(m, r, c, K):
        k = K
        while k<n:
            # check the border
            for l in 0..k:
                if m[r+k, c+l] == 0 or m[r+l, c+k] == 0: # consider the left and bottom borders
                    break while
            if m[r+k, c+k] == 0 # don't forget the corner
                break while
            k += 1
        return k
    
    for r in 0..n:
        for c in 0..n: 
            K = max(M[r-1,c-1], M[r-1,c], M[r,c-1]) - 1 # add boundary check, K = 0 if r,c = 0,0
            M[r,c] = largest_square_size(m, r, c, K)
            if M[r,c] > K:
                N += subsquares_count(M[0,0]) - subsquares_count(K)