Queries on number of Binary sub-matrices of Given size

Given a Binary Matrix of size N X M, the task is to answer Q queries of the following type;

Query(a, b): Find the number of sub matrices of size a X a with each of its element consisting of the Binary Number b.

We basically need to find submatrices of given sizes with all 1s or all 0s.

Examples:

Input : N = 5, M = 4
m[][] = { { 0, 0, 1, 1 },
{ 0, 0, 1, 0 },
{ 0, 1, 1, 1 },
{ 1, 1, 1, 1 },
{ 0, 1, 1, 1 }
}
Q = 2
Query 1 : a = 2, b = 1
Query 2 : a = 2, b = 0
Output : 4 1

Explanation:
For Query 1,
0011  0011  0011  0011
0010  0010  0010  0010
0111  0111  0111  0111
1111  1111  1111  1111
0111  0111  0111  0111

For Query 2,
0011
0010
0111
1111
0111

Input : N = 5, M = 4
m[][] = { { 0, 0, 1, 1 },
{ 0, 0, 1, 0 },
{ 0, 1, 1, 1 },
{ 1, 1, 1, 1 },
{ 0, 1, 1, 1 }
}

Q = 1
Query 1 : a = 3, b = 1
Output : 1

Recommended: Please try your approach on {IDE} first, before moving on to the solution.

The idea is to use Dynamic Programming to solve the problem. First declare a 2D array dp[][], where value at dp[i][j] (say K) indicates the size of the largest square sub-matrix (K X K) that can be formed whose all elements are equal to m[i][j] and (i, j) is the last element (south-east) of the sub matrix. Now, dp[i][j] can be defined as:

1) If i = 0 OR j = 0 In this Case, dp[i][j] = 1, because only 1 X 1 is the only square matrix that can be formed at 0th row or 0th column whose all elements are equal
to m[i][j] and the last element is (i, 0) or (0, j).

2) If m[i][j] = m[i-1][j] = m[i][j-1] = m[i-1][j-1] dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1, if the binary number at m[i][j] is equal to the binary number at m[i-1][j], m[i-1][j-1] and m[i][j-1]. Because if the current binary number is equal to all the three binary numbers it will form a 2 X 2 square sub-matrix where all the elements are equal. Also, it will contribute 1 more row and column to the square matrix with all equal element at position m[i-1][j], m[i-1][j-1] and m[i][j-1].

dp[i][j] = 1, if above conditions do not meet because a single cell will always contribute a 1 X 1 sub matrix.

Now, traverse the 2D dp[][] array and calculate the frequency (freq0[] for the element 0, freq1[] for the element 1) of all the distinct values i.e distinct sizes of square sub-matrix for both 0s and 1s.
Observe, that to count the square sub-matrix of size Y X Y, then Y+1 X Y+1 will also contribute 1 count. Suppose we need to count 2 X 2 matrix and dp[][]=

...22
...23

Here, the frequency of two is 3 but observe element where dp[i][j] = 3 is also contributing a 2 X 2 square sub-matrix.
So, find the cumulative sum of the frequency for both freq0[] and freq1[].

Below is the implementation of this approach:

C++

 // CPP Program to answer queries on number of // submatrix of given size #include using namespace std;    #define MAX 100 #define N 5 #define M 4    // Return the minimum of three numbers int min(int a, int b, int c) {     return min(a, min(b, c)); }    // Solve each query on matrix void solveQuery(int n, int m, int mat[N][M], int q,                               int a[], int binary[]) {     int dp[n][m], max = 1;        // For each of the cell.     for (int i = 0; i < n; i++) {         for (int j = 0; j < m; j++) {                // finding submatrix size of oth row              // and column.             if (i == 0 || j == 0)                 dp[i][j] = 1;                // intermediate cells.             else if ((mat[i][j] == mat[i - 1][j]) &&                      (mat[i][j] == mat[i][j - 1]) &&                       (mat[i][j] == mat[i - 1][j - 1])) {                    dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1],                                dp[i][j - 1])                            + 1;                    if (max < dp[i][j])                     max = dp[i][j];             }                else                 dp[i][j] = 1;         }     }        int freq0[MAX] = { 0 }, freq1[MAX] = { 0 };        // Find frequency of each distinct size      // for 0s and 1s.     for (int i = 0; i < n; i++) {         for (int j = 0; j < m; j++) {             if (mat[i][j] == 0)                 freq0[dp[i][j]]++;             else                 freq1[dp[i][j]]++;         }     }        // Find the Cumulative Sum.     for (int i = max - 1; i >= 0; i--) {         freq0[i] += freq0[i + 1];         freq1[i] += freq1[i + 1];     }        // Output the answer for each query     for (int i = 0; i < q; i++) {         if (binary[i] == 0)             cout << freq0[a[i]] << endl;         else             cout << freq1[a[i]] << endl;     } }    // Driver Program int main() {     int n = 5, m = 4;     int mat[N][M] = {         { 0, 0, 1, 1 },         { 0, 0, 1, 0 },         { 0, 1, 1, 1 },         { 1, 1, 1, 1 },         { 0, 1, 1, 1 }     };     int q = 2;     int a[] = { 2, 2 };     int binary[] = { 1, 0 };        solveQuery(n, m, mat, q, a, binary);        return 0; }

Java

 // Java Program to answer queries on number of // submatrix of given size import java.io.*;    class GFG {        static int MAX = 100;     static int N = 5;     static int M = 4;            // Return the minimum of three numbers     static int min(int a, int b, int c)     {         return Math.min(a, Math.min(b, c));     }            // Solve each query on matrix     static void solveQuery(int n, int m, int mat[][],                         int q, int a[], int binary[])     {         int dp[][] = new int[n][m];          int max = 1;                // For each of the cell.         for (int i = 0; i < n; i++) {             for (int j = 0; j < m; j++) {                        // finding submatrix size of oth row                  // and column.                 if (i == 0 || j == 0)                     dp[i][j] = 1;                        // intermediate cells.                 else if ((mat[i][j] == mat[i - 1][j])                        && (mat[i][j] == mat[i][j - 1])                  && (mat[i][j] == mat[i - 1][j - 1]))                  {                            dp[i][j] = min(dp[i - 1][j],                                dp[i - 1][j - 1],                                 dp[i][j - 1]) + 1;                            if (max < dp[i][j])                         max = dp[i][j];                 }                        else                     dp[i][j] = 1;             }         }                int freq0[] = new int[MAX];         int freq1[] = new int[MAX];                // Find frequency of each distinct size          // for 0s and 1s.         for (int i = 0; i < n; i++) {             for (int j = 0; j < m; j++) {                 if (mat[i][j] == 0)                     freq0[dp[i][j]]++;                 else                     freq1[dp[i][j]]++;             }         }                // Find the Cumulative Sum.         for (int i = max - 1; i >= 0; i--) {             freq0[i] += freq0[i + 1];             freq1[i] += freq1[i + 1];         }                // Output the answer for each query         for (int i = 0; i < q; i++) {             if (binary[i] == 0)                 System.out.println( freq0[a[i]]);             else                 System.out.println( freq1[a[i]]);         }     }            // Driver Program        public static void main (String[] args)      {         int n = 5, m = 4;         int mat[][] = { { 0, 0, 1, 1 },                         { 0, 0, 1, 0 },                         { 0, 1, 1, 1 },                         { 1, 1, 1, 1 },                         { 0, 1, 1, 1 } };         int q = 2;         int a[] = { 2, 2 };         int binary[] = { 1, 0 };                solveQuery(n, m, mat, q, a, binary);     } }    // This code is contributed by anuj_67.

C#

 // C# Program to answer  // queries on number of // submatrix of given size using System;    class GFG  {     static int MAX = 100;     // static int N = 5;     // static int M = 4;            // Return the minimum     // of three numbers     static int min(int a,                     int b,                     int c)     {         return Math.Min(a, Math.Min(b, c));     }            // Solve each query on matrix     static void solveQuery(int n, int m,                             int [,]mat, int q,                             int []a, int []binary)     {         int [,]dp = new int[n, m];          int max = 1;                // For each of the cell.         for (int i = 0; i < n; i++)          {             for (int j = 0; j < m; j++)              {                        // finding submatrix size                  // of oth row and column.                 if (i == 0 || j == 0)                     dp[i, j] = 1;                        // intermediate cells.                 else if ((mat[i, j] == mat[i - 1, j]) &&                           (mat[i, j] == mat[i, j - 1]) &&                           (mat[i, j] == mat[i - 1, j - 1]))                 {                             dp[i, j] = min(dp[i - 1, j],                                    dp[i - 1, j - 1],                                    dp[i, j - 1]) + 1;                            if (max < dp[i, j])                         max = dp[i, j];                 }                        else                     dp[i, j] = 1;             }         }                int []freq0 = new int[MAX];         int []freq1 = new int[MAX];                // Find frequency of each          // distinct size for 0s and 1s.         for (int i = 0; i < n; i++)          {             for (int j = 0; j < m; j++)              {                 if (mat[i, j] == 0)                     freq0[dp[i, j]]++;                 else                     freq1[dp[i, j]]++;             }         }                // Find the Cumulative Sum.         for (int i = max - 1; i >= 0; i--)          {             freq0[i] += freq0[i + 1];             freq1[i] += freq1[i + 1];         }                // Output the answer         // for each query         for (int i = 0; i < q; i++)         {             if (binary[i] == 0)                 Console.WriteLine(freq0[a[i]]);             else                 Console.WriteLine(freq1[a[i]]);         }     }            // Driver Code     public static void Main ()      {         int n = 5, m = 4;         int [,]mat = {{0, 0, 1, 1},                       {0, 0, 1, 0},                       {0, 1, 1, 1},                       {1, 1, 1, 1},                       {0, 1, 1, 1}};         int q = 2;         int []a = {2, 2};         int []binary = {1, 0};                solveQuery(n, m, mat,                     q, a, binary);     } }    // This code is contributed by anuj_67.

Output:

4
1

Time Complexity of the above algorithm is O(n * m)

My Personal Notes arrow_drop_up Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.

Improved By : vt_m