简体   繁体   中英

Backtracking in a grid

Let's say there's a 2D grid of 1s and 0s, for example -

0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 0

The grid is "collapsed" to form a smaller grid of 1 fewer row and 1 fewer column, so the above example would be "collapsed" to form a grid of 3 rows and 3 columns.

The new values are determined by the following rule -

new_grid[i][j] is dependent on 
  i) old_grid[i][j], 
 ii) old_grid[i][j+1], 
iii) old_grid[i+1][j] 
 iv) old_grid[i+1][j+1]

If exactly one of the above values are 1, then new_grid[i][j] will be 1, else 0.

So for the example grid, out of [0][0], [0][1], [1][0] and [1][1] , only [0][1] is 1 , so [0][0] in the new grid will be 1. Similarly, out of [0][1], [0][2], [1][1] and [1][2] , both [0][1] and [1][2] are 1 , so [0][1] in new_grid will be 0.

The input is given in the form of new_grid values. I have to find out the number of possible configurations of old_grid , such that new_grid is possible through the collapsing rules provided.


My approach

The backtracking solution that I have currently thought of goes like this -

  1. Identify imaginary 2X2 boxes for each 1-valued cell in the old grid which would correspond to the appropriate cell in the new grid.

  2. All of these boxes will contain exactly one cell with value 1, so put 1 in a random cell in each box.

  3. Recursively check if putting 1s in the random cells ensures that each box still retains exactly one cell with value 1.

  4. If a grid configuration is finally obtained where every box contains exactly one cell with value 1, check if the configuration can be "collapsed" to get the new grid.

  5. If not, then repeat the process with a different cell with the value 1.

If there are some cells in the old grid which don't come under any "box", then they are what I have termed as "doesn't-matter" cells.


For example -

1 1 
0 0

For the above new_grid , the old_grid can be -

1 0 1
0 0 0 
0 0 0           

or

1 0 1
0 0 0
1 1 1

The last row's cells are "doesn't-matter" cells since they don't come under any 2X2 box and they can all be 1 s or 0 s to be valid configurations (I am thinking that is the extent to which we can flexibly manipulate them, although I am not sure).

My question is this - This algorithm is quite possibly exponential in growth and it will take a lot of time for a grid of say, 50X10 .

Is there any other way to solve this question? Or is there any clever algorithm to not go through every possible configuration in order to count them?

Hmm, so I have thought of a 2x3 newGrid like so:

newGrid: 0 1 0
         0 0 0

Which would need to be produced by either one of these 3x4 oldGrids:
Each _ can be 1 or 0

oldGrid 1: _ 0 1 _
           _ 0 0 _
           _ _ _ _

oldGrid 2: _ 1 0 _
           _ 0 0 _
           _ _ _ _

oldGrid 3: _ 0 0 _
           _ 1 0 _
           _ _ _ _

oldGrid 4: _ 0 0 _
           _ 0 1 _
           _ _ _ _

And all the remaining 8 spots can be populated in 2^8 ways. So the answer would be 4 * 2^8

However, imagine if newGrid had more than one 1:

newGrid: 1 1 0
         0 0 0

Which will have these 8 oldGrids:

oldGrid 1: 1 0 _ _
           0 0 _ _
           _ _ _ _

oldGrid 2: 0 1 _ _
           0 0 _ _
           _ _ _ _

oldGrid 3: 0 0 _ _
           1 0 _ _
           _ _ _ _

oldGrid 4: 0 0 _ _
           0 1 _ _
           _ _ _ _

oldGrid 5: _ 1 0 _
           _ 0 0 _
           _ _ _ _

oldGrid 6: _ 0 1 _
           _ 0 0 _
           _ _ _ _

oldGrid 7: _ 0 0 _
           _ 1 0 _
           _ _ _ _

oldGrid 8: _ 0 0 _
           _ 0 1 _
           _ _ _ _

from oldGrid 1 I would have produced 2^8 combinations. But notice how some of those will be the same solutions produced by oldGrid 6 . It's those that look like this:

oldGrid 1.1: 1 0 1 _
             0 0 0 _
             _ _ _ _

And it has 2^6 solutions.

So oldGrid 1 has 2^8 - 2^6 solutions that don't conflict with oldGrid 6 .
And oldGrid 6 has 2^6 solutions that don't conflict with oldGrid 1 .
And together they have (2^8 - 2^6) + (2^8 - 2^6) + 2^6 solutions.

1 and 6, 1 and 8, 2 and 5, 3 and 6, 3 and 8, 4 and 7 have conflicting solution spaces, each one with 2^6.

Which I think means the number of solutions are 8 * 2^8 - 6 * 2^6.
And that is:

numberOfSolutions = numberOf1s * 4 * 2^(oldGridSize-4) - overlappingSolutionsCount
overlappingSolutionsCount = numberOfOverlappingPairs * 2^(oldGridSize-4-overlapAreaSize)  

How to calculate the overlap

function countOverlappingSolutions(newGrid: an MxN matrix) {
    result = 0
    oldGridSize = (M+1) * (N+1)
    for each pair of 1s in the newGrid:
        let manhattanDistance = manhattan distance between the 1s in the pair
        let overlapAreaSize = 0

        if the 1s are in the same row or column
            if manhattanDistance == 1:
                overlapSize = 2
        else if manhattanDistance == 2
            overlapAreaSize = 1

        result += 2^(oldGridSize -4 -overlapAreaSize)

    return result
}

The final algorithm:

let newGrid be a MxN matrix
let numberOf1s = number of 1s in newGrid
let oldGridSize = (M+1) * (N+1)

result = numberOf1s * 4 * 2^(oldGridSize - 4) - countOverlappingSolutions(newGrid)

I couldn't make the effort to write python code but I hope the solution is correct and/or shows the way

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM