Search code examples
c++arraysloopsdynamic-programmingsub-array

Traversing all the subarrays of a 2-D array


I have a 2-D array given of size P*Q and I have to answer K questions based on the array. The 2-D array given consists of numbers 0 and 1. For each question, we have to count the maximum size of any square subarray in which no two same elements are adjacent. For example if P=Q=8 and our given array be

00101010
00010101
10101010
01010101
10101010
01010101
10101010
01010101

Then the question Ki allows us to do Ki number of flips(0's to 1 or 1's to 0.)

Here K=4(number of questions)
1 2 0 10001
Output: 7 8 6 8

I have understood that as for K1=1, we can change the value of array index(1,1) to 1 and get a 7*7 sized valid matrix, the output is 7. If we have Ki>=2 our answer will be 8. What I think is that we have to maintain an array ans[k] which stores the maximum size of a square sub matrix which is valid. For this, we can start each index of the original array and traverse through its sub-arrays and count the value of maximum size for flip=i if we start from this index. We have to do this for the subarrays starting from each index and then store the maximum of them in flip[i]. I have problems implementing this as I don't know how to traverse all the sub-arrays for a given index. I'm trying this for so long but still not achieving it. Can anyone please help?


Solution

  • It helps to simplify the problem to depend only on individual values (rather than pairs of neighboring values). So XOR the grid with each perfect checkerboard:

    01111111  10000000
    10111111  01000000
    11111111  00000000
    11111111  00000000
    11111111  00000000
    11111111  00000000
    11111111  00000000
    11111111  00000000
    

    where the goal is now to find the largest square in either grid that has no more than K_i 0s (obviously favoring the left one here).

    Start with K_i=0. To find the largest square of 1s, compute for each cell the number of 1s in a row and a column starting at it (0 for a cell that contains a 0); the largest square with that cell as its upper-left corner (assuming it's a 1) is then one more than the minimum of the row length of its right neighbor, the column length of its lower neighbor, and the square-size of its lower-right neighbor. (All these are 0 for the non-existent cells outside the grid.) Visit the cells in diagonal-major order to have these values available when you need them; note the largest square size produced.

    To generalize to K_i>0, store for each cell those three values (row length, column length, and square size) for each number of flips up to K_i. A cell with a 1 adds 1 to each row/column length as before, while a cell with a 0 shifts those lengths to the next flip count, discarding those whose flip count is now too large and adding a new value of 0 for 0 flips. For each combination of row-length-east, column-length-south, and square-size-southeast, each with a flip count, a cell gets a candidate square size that is their minimum with the sum of their flip counts, plus one if the cell is a 0 itself. For each flip count (that isn't too large), keep the largest square size, noting if it is the largest so far encountered (for that flip count).

    Note that the brute-force solution may be nearly as fast when the squares are much smaller than the array, since it need visit each one only a small number of times.