给定大小为NXM的二进制矩阵,任务是回答以下类型的Q个查询;
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.
我们基本上需要找到具有全1或全0的给定大小的子矩阵。
例子:
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
想法是使用动态编程来解决该问题。首先声明2D数组dp [] [] ,其中dp [i] [j]的值(例如K)表示可以形成的最大平方子矩阵(KXK)的大小,其所有元素均等于m [ i] [j]和(i,j)是子矩阵的最后一个元素(东南)。现在,可以将dp [i] [j]定义为:
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.
现在,遍历二维dp [] []数组并计算所有不同值的频率(元素0的freq0 [],元素1的freq1 []),即0s和1s的正方形子矩阵的不同大小的频率。
观察到,要对大小为YXY的平方子矩阵进行计数,则Y + 1 X Y + 1也将贡献1个计数。假设我们需要计算2 X 2矩阵和dp [] [] =
...22
...23
在这里,二的频率为3,但是dp [i] [j] = 3的观察元素也贡献了2 X 2平方的子矩阵。
因此,找到freq0 []和freq1 []的频率的累加和。
以下是此方法的实现:
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.
4
1
上述算法的时间复杂度为O(n * m)