Optimal Square Covering in 2D Matrix (Minimize Coverage Cost) - algorithm

I came across the following programming challenge recently:
Statement
Consider a 2D square matrix of size NxN containing 0s and 1s. You have to cover all the 1s in the matrix using squares of size 1, 2 or 3. The coverage cost using square of size 1 is 2, using square of size 2 is 4 and using square of size 3 is 7. The objective is to find the minimum coverage cost to cover all the 1s in matrix.
Constraints
1 <= N <= 100
General Comments
Overlapping covering squares are allowed.
It is not necessary that the covering square should cover only 1s -
they may cover cells containing 0s as well.
Example
Consider the following matrix as an example:
0 0 0 0 0 0 0 0
0 1 1 0 0 0 0 0
0 1 1 1 0 0 0 0
0 0 1 1 1 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 1 1 0
0 0 0 0 0 0 1 0
In above example, minimum coverage cost is 7x1 + 4x2 + 2x1 = 17. Another covering is possible with minimum coverage cost of 7x1 + 4x1 + 2x3 = 17.
My Approach
I tried to approach the problem in the following manner:
Use square of size 3 to cover 1s where number of 1s in any 3x3 area is >= 5. Remove those 1s from the matrix.
Next, use square of size 2 to cover 1s where number of 1s in any 2x2
area is >= 2. Remove those 1s from the matrix.
Cover remaining 1s with sqaure of size 1.
This approach is greedy and is not optimal. For the example above, my approach gives answer 7x1 + 4x2 + 2x2 = 19 which is not optimal.
Any pointers about how to approach this problem or references to known problems which can be used to solve this one are appreciated. Thanks.
Update
Taking a cue from #bvdb answer, I updated the approach to select the coverage squares based on the number of 1s they are covering. However, the approach is still non-optimal. Consider a scenario where we have the following arrangement:
1 0 1
0 0 0
1 0 1
This arrangement will be covered using 4 coverage squares of size 1 whereas they must be covered using 1 square of size 3. In general, 5 1s in 3x3 area must be covered using different strategies based on how they are spread in the area. I can hardcode it for all types of cases, but I am looking for an elegant solution, if it exists.

Your problem is a typical Packing problem.
Your approach of fitting the biggest box first makes perfect sense.
A simple way to make your algorithm better, is to just give preference to 3x3 squares with maximum conent.
Example:
Use square of size 3 to cover 1s where number of 1s in any 3x3 area is = 9. Remove those 1s from the matrix.
Idem, but where area is = 8.
Idem, but where area is = 7.
Idem, but where area is = 6.
Next, use square of size 2 to cover 1s where number of 1s in any 2x2 area is = 4. Remove those 1s from the matrix.
etc ...
Monte carlo method
But if you want to add overlap, then it gets more tricky. I am sure you could work it out mathematically. However, when logic becomes tricky, then the Monte Carlo method always comes to mind:
Monte Carlo methods (or Monte Carlo experiments) are a broad class of computational algorithms that rely on repeated random sampling to obtain numerical results. They are often used in physical and mathematical problems and are most useful when it is difficult or impossible to use other mathematical methods.
Monte Carlo trades coded logic for speed and randomness:
STEP 1: repeat 4 times:
cor = randomCoordinate()
if ( hasContent(cor, 3) ) then putSquare(cor, 3)
STEP 2: repeat 16 times:
cor = randomCoordinate()
if ( hasContent(cor, 2) ) then putSquare(cor, 2)
STEP 3: corList = getFreeSquaresWithContent()
putSquare(corlist, 1)
calculateScore()
store used squares and score.
This code should be simple but really fast.
Then run this 100.000 times, and keep the top 10 scores.
Which 3x3 squares did the winners use most often?
Use this information as a "starting position".
Now, run it again from STEP2 using this starting position.
This means that the 100.000 iterations don't have to focus on the 3x3 squares any more, they immediately start adding 2x2 squares.
PS: The number of iterations you do (e.g. 100.000) is really a matter of the required response time and the required accuracy. You should test this to find out what is acceptable.

If you are looking for a deterministic approach.
I think the best thing to do is to sort all possible patterns in an optimal order. There are only 394 relevant patterns. There is no need to hardcode them, you can generate them on-the-fly.
First our definitions (rules of the game). Each square has a size and a cost.
class Square
{
private int size;
private int cost;
Square(int pSize, int pCost)
{
size = pSize;
cost = pCost;
}
}
And there are only 3 types of squares. squareOne keeps the cost of a 1x1 matrix, squareTwofor a 2x2 and squareThree for a 3x3 matrix.
Square squareOne = new Square(1, 2);
Square squareTwo = new Square(2, 4);
Square squareThree = new Square(3, 7);
List<Square> definitions = Arrays.asList(squareOne, squareTwo, squareThree);
We are going to have to store each pattern with its cost, number of hits, and its cost per hit (efficiency). So here follows the class that I am using to store it. Note that this class contains methods that help to perform the sorting as well as conversions to a matrix of boolean's (1/0 values).
class ValuedPattern implements Comparable<ValuedPattern>
{
private long pattern;
private int size;
private int cost;
private double costPerHit;
private int hits;
ValuedPattern(long pPattern, int pSize, int pCost)
{
pattern = pPattern;
cost = pCost;
size = pSize;
// calculate the efficiency
int highCount = 0;
BitSet set = BitSet.valueOf(new long[]{pattern});
for (int i = 0; i < set.size(); i++)
{
if (set.get(i)) highCount++;
}
hits = highCount;
costPerHit = (double) cost / (double) hits;
}
public boolean[][] toArray()
{
boolean[][] patternMatrix = new boolean[size][size];
BitSet set = BitSet.valueOf(new long[]{pattern});
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
patternMatrix[i][j] = set.get(i * size + j);
}
}
return patternMatrix;
}
/**
* Sort by efficiency
* Next prefer big matrixes instead of small ones.
*/
#Override
public int compareTo(ValuedPattern p)
{
if (p == null) return 1;
if (costPerHit < p.costPerHit) return -1;
if (costPerHit > p.costPerHit) return 1;
if (hits > p.hits) return -1;
if (hits < p.hits) return 1;
if (size > p.size) return -1;
if (size < p.size) return 1;
return Long.compare(pattern, p.pattern);
}
#Override
public boolean equals(Object obj)
{
if (! (obj instanceof ValuedPattern)) return false;
return (((ValuedPattern) obj).pattern == pattern) &&
(((ValuedPattern) obj).size == size);
}
}
Next we are going to store all possible patterns in a sorted collection (i.e. a TreeSet sorts its content automatically using the compareTo method of the object).
Since your patterns are just 0 and 1 values, you can think of them as numeric values (long is a 64bit integer which is more than enough) which can be converted later to a boolean matrix. The size of the pattern is the same as the number of bits of that numeric value. Or in other words there are 2^x possible values, with x being the number of cells in your pattern.
// create a giant list of all possible patterns :)
Collection<ValuedPattern> valuedPatternSet = new TreeSet<ValuedPattern>();
for (Square square : definitions)
{
int size = square.size;
int bits = size * size;
long maxValue = (long) Math.pow(2, bits);
for (long i = 1; i < maxValue; i++)
{
ValuedPattern valuedPattern = new ValuedPattern(i, size, square.cost);
// filter patterns with a rediculous high cost per hit.
if (valuedPattern.costPerHit > squareOne.cost) continue;
// and store the result for later
valuedPatternSet.add(valuedPattern);
}
}
After composing the list, the patterns are already sorted according to efficiency. So now you can just apply the logic that you already have.
// use the list in that order
for (ValuedPattern valuedPattern : valuedPatternSet)
{
boolean[][] matrix = valuedPattern.toArray();
System.out.println("pattern" + Arrays.deepToString(matrix) + " has cost/hit: " + valuedPattern.costPerHit);
// todo : do your thing :)
}
The demo code above outputs all patterns with their efficiency. Note that smaller patterns sometimes have a better efficiency than the bigger ones.
Pattern [[true, true, true], [true, true, true], [true, true, true]] has cost/hit: 0.7777777777777778
Pattern [[true, true, true], [true, true, true], [true, true, false]] has cost/hit: 0.875
Pattern [[true, true, true], [true, true, true], [true, false, true]] has cost/hit: 0.875
Pattern [[true, true, true], [true, true, true], [false, true, true]] has cost/hit: 0.875
...
The entire thing runs in just a couple of ms.
EDIT:
I added some more code, which I am not going to drop here (but don't hesitate to ask, then I'll e-mail it to you). But I just wanted to show the result it came up with:
EDIT2:
I am sorry to tell you that you are correct to question my solution. It turns out there is a case where my solution fails:
0 0 0 0 0 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 0 0 0 0 0
My solution is greedy, in the sense that it immediatly tries to apply the most efficient pattern:
1 1 1
1 1 1
1 1 1
Next only the following remains:
0 0 0 0 0 0
0 _ _ _ 1 0
0 _ _ _ 1 0
0 _ _ _ 1 0
0 1 1 1 1 0
0 0 0 0 0 0
Next it will use three 2x2 squares to cover the remains.
So the total cost = 7 + 3*4 = 19
The best way of course would have been to use four 2x2 squares.
With a total cost of 4*4 = 16
Conclusion: So, even though the first 3x3 was very efficient, the next 2x2 patterns are less efficient. Now that you know this exception you could add it to the list of patterns. E.g. a square with size 4 has cost 16. However, that wouldn't solve it, a 3x3 would still have a lower cost/hit and would always be considered first. So, my solution is broken.

Related

Choosing the Best Matrix

I am given X matrices of size Ni*Mi where 1<=N<=4 and 1<=M<=4, for all 1 <= i <= X
The game consists of choosing any rectangle (submatrix) from one of the given X matrices and removing this submatrix.
For Example: we have 1 matrix of size 4x4. Player 1 can choose a submatrix of size 4x4 (the entire matrix in this case) and remove it. Or they can choose a submatrix of 2x2 or 1x1 or 2x3 or any valid submatrix and remove it from the 4x4 matrix and we have the remaining matrix left in the game.
The player who can't make a move loses.
Which player wins?
Both Player Plays optimally.
This problem is solved with the Sprague Grundy theorem, which says that when you xor the nimbers of the individual matrices, then the player to move only loses when the result is 0 (because any move will turn the losing position in a winning position and the other player can then turn the winning position in a losing position again and so on, it's the nature of nim-like games).
The nimbers are calculated recursively, a nimber of a matrix is the mex (minimal exclusive = the smallest non-negative integer not present in the collection) of the nimbers of all reachable states.
All 0s is 0, you don't have a valid move and therefore it is a loss (0).
Exactly one 1 is 1 because the only reachable position is 0 and mex(0) = 1.
For two ones we have to decide whether they are adjacent or not, adjacent = mex(0, 1) = 2, not adjacent = mex(1) = 0... and so on.
Example:
1 0 0 0 1 1 0 1 1
0 0 1 1 0 0 0 1 1
0 0 1 0 0 0 1
0 0 0 0
= = =
2 xor 3 xor 1 = 0 => player to move loses.
A fast implementation could look like this:
Calculate the nimbers for the 16 (10 with symmetries) different cases in advance and store them in an array.
Assign result = 0
result = result xor nimbers[readRowCount()][readColCount()]
Repeat 3. until all matrix dimensions are read
if result != 0 then the first player wins else the second player
Example 2: nimber calculation
matrix:
1 1
1 1
valid moves:
0 1* 1 0* 1 1* 1 1* 0 0 1 1+ 0 0+ 1 0+ 0 1+
1 1 1 1 0 1 1 0 0 0 0 0 1 1 1 0 0 1
=
0 by definition
The other matrices can be grouped into 2 groups * and + because of symmetries.
Reachable positions from *:
0 1 0 1 0 0
0 1 1 0 0 1
= = =
1 = mex(0), because the only reachable position has a nimber of 0
0 = mex(1), because the only reachable position has a nimber of 1
2 = mex(0,1), because the reachable positions have nimbers of 0 and 1
==> the nimber for * is mex(0, 1, 2) = 3.
==> we already know now that the nimber of + is 2.
==> the nimber of the given matrix is mex(0, 2, 3) = 1.
(Before maraca posted his answer about the Sprague Grundy theorem, I was trying to identify an optimal strategy for the game; I'll describe it below, maybe it can also be used to code a solution.)
The outcome of the game is the result of whether each rectangle is removed in an odd or even number of moves. If the total number of moves is odd, player 1 wins; if it is even, player 2 wins.
Let's take a look at the possible rectangles:
For all "normal" rectangles (except 2x2 and 1x1) the player who first removes part of it can decide whether it is completely removed in an odd number of moves (e.g. by removing it completely in one go) or in an even number of moves; the cells indicated in yellow show a first move which leaves the player in control.
For "thin" rectangles which are only 1 cell wide, the odd/even decision is taken immediately (by either removing the whole rectangle, or leaving 1 cell). For the other "normal" rectangles, the decision is delayed from 1 up to 3 moves, depending on the other player's actions.
The 1x1 rectangle can only be removed in one move (i.e. an odd number of moves). The 2x2 rectangle can be removed in one move, but the player cannot force an even number of moves by removing only part of it; the other player can always decide odd or even.
As you can see from the moves indicated in yellow in the images, a move which creates a symmetrical situation (e.g. dividing the 4x4 square into two 4x1 rectangles) leaves the person who created this situation in control of the outcome for this rectangle. He can e.g. force an even number of moves for this rectangle like this:
This is also true for the whole game: if a player's move results in a symmetrical situation (e.g. two identical L-shapes and four 3x1 rectangles) he can respond to the other player's moves by mirroring them, and then when there is only one rectangles greater than 1x1 left, he can choose to remove it completely or leave one cell (depending on whether the number of single cells left over is odd or even) and win the game.
So the strategy comes down to creating a symmetrical situation, and not giving the other player the opportunity to create a symmetrical situation.
Note: a more complicated symmetry can be created by removing the center of a 3x3, 4x3 or 4x4 rectangle and creating a loop. Instead of mirroring the other player's moves, you then rotate them by 180 degrees (i.e. point-mirroring).
A few game results based on these ideas:
One rectangle: player 1 wins.
Two identical rectangles: player 2 wins.
A 1x1 and a thin rectangle: player 1 wins.
A 1x1 and a 2x2 rectangle: player 2 wins.
A 1x1 and a larger rectangle: player 1 wins.
A 2x2 and a thin rectangle: player 1 wins.
A 2x2 and a larger rectangle: player 1 wins.
Three identical rectangles: player 1 wins.
A 1x1, a 2x2 and any other rectangle: player 1 wins.
An even number of identical rectangles: player 2 wins.
An even number of identical and any other rectangle: player 1 wins.
An odd number of identical rectangles: player 1 wins.
Below is an implementation of the Sprague-Grundy theorem, as explained in maraca's answer. It uses a list of pre-calculated nimbers for rectangles up to 4x4.
function outcome(rectangles) {
var n = 0, nimbers = [[1,2,3,4],[2,1,5,8],[3,5,4,7],[4,8,7,3]];
for (var i = 0; i < rectangles.length; i++) {
n ^= nimbers[rectangles[i][0] - 1][rectangles[i][1] - 1];
}
return n > 0 ? 1 : 2;
}
document.write("Player " + outcome([[3,3],[3,4],[4,4]]) + " wins.<br>");
document.write("Player " + outcome([[1,1],[2,2],[3,3],[4,4]]) + " wins.");
The nimber of any 4x4 matrix can be calculated with the algorithm below. The 4x4 matrices are represented by 16-bit patterns, e.g. 65535 is a matrix filled with ones. A list of all rectangles (possible moves), represented as bit patterns, is pre-calculated.
function nimber(matrix) {
var rect = [ 1, 2, 3, 4, 6, 7, 8, 12, 14, 15,
16, 17, 32, 34, 48, 51, 64, 68, 96, 102,
112, 119, 128, 136, 192, 204, 224, 238, 240, 255,
256, 272, 273, 512, 544, 546, 768, 816, 819, 1024,
1088, 1092, 1536, 1632, 1638, 1792, 1904, 1911, 2048, 2176,
2184, 3072, 3264, 3276, 3584, 3808, 3822, 3840, 4080, 4095,
4096, 4352, 4368, 4369, 8192, 8704, 8736, 8738,12288,13056,
13104,13107,16384,17408,17472,17476,24576,26112,26208,26214,
28672,30464,30576,30583,32768,34816,34944,34952,49152,52224,
52416,52428,57344,60928,61152,61166,61440,65280,65520,65535];
var memo = [0]; // nimber of empty matrix is 0
return nim(matrix);
function nim(current) {
if (memo.hasOwnProperty(current)) return memo[current]; // use memoized value
var exclude = []; // set of nimbers of reachable states
for (var i = 0; i < rect.length; i++) {
if ((current & rect[i]) == rect[i]) { // this rectangle is a valid move
var next = current & ~rect[i]; // remove rectangle
exclude[nim(next)] = true; // recurse and add nimber to set
}
}
return (memo[current] = mex(exclude)); // memoize this nimber
}
function mex(n) { // minimum excludant of nimber set
var m = 0;
while (n[m]) ++m;
return m;
}
}
document.write(nimber(65535)); // 0b1111111111111111 represents a filled 4x4 matrix
The list of 16-bit patterns representing the rectangles of all sizes, positions and orientations in a 4x4 matrix can be generated like this:
function rectangles(width, height) {
var rect = [], line = (1 << width) - 1;
for (var y = 0; y < height; y++) {
for (var x = 0; x < width; x++) {
for (var h = 1; h <= height - y; h++) {
for (var w = 1; w <= width - x; w++) {
var bits = ((line >> (width - w)) << (width - x - w)) << (y * width)
for (var row = 1; row < h; row++) {
bits |= (bits << width);
}
rect.push(bits);
}
}
}
}
return rect;
}
document.write(rectangles(4,4));

Why does this maximum product subarray algorithm work?

The problem is to find the contiguous subarray within an array (containing at least one number) which has the largest product.
For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product 6.
Why does the following work? Can anyone provide any insight on how to prove its correctness?
if(nums == null || nums.Length == 0)
{
throw new ArgumentException("Invalid input");
}
int max = nums[0];
int min = nums[0];
int result = nums[0];
for(int i = 1; i < nums.Length; i++)
{
int prev_max = max;
int prev_min = min;
max = Math.Max(nums[i],Math.Max(prev_max*nums[i], prev_min*nums[i]));
min = Math.Min(nums[i],Math.Min(prev_max*nums[i], prev_min*nums[i]));
result = Math.Max(result, max);
}
return result;
Start from the logic-side to understand how to solve the problem. There are two relevant traits for each subarray to consider:
If it contains a 0, the product of the subarray is aswell 0.
If the subarray contains an odd number of negative values, it's total value is negative aswell, otherwise positive (or 0, considering 0 as a positive value).
Now we can start off with the algorithm itself:
Rule 1: zeros
Since a 0 zeros out the product of the subarray, the subarray of the solution mustn't contain a 0, unless only negative values and 0 are contained in the input. This can be achieved pretty simple, since max and min are both reset to 0, as soon as a 0 is encountered in the array:
max = Math.Max(0 , Math.Max(prev_max * 0 , prev_min * 0));
min = Math.Min(0 , Math.Min(prev_max * 0 , prev_min * 0));
Will logically evaluate to 0, no matter what the so far input is.
arr: 1 1 1 1 0 1 1 1 0 1 1 1 0 1 1 0
result: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
min: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
max: 1 1 1 1 0 1 1 1 0 1 1 1 0 1 1 0
//non-zero values don't matter for Rule 1, so I just used 1
Rule 2: negative numbers
With Rule 1, we've already implicitly splitted the array into subarrays, such that a subarray consists of either a single 0, or multiple non-zero values. Now the task is to find the largest possible product inside that subarray (I'll refer to that as array from here on).
If the number of negative values in the array is even, the entire problem becomes pretty trivial: just multiply all values in the array and the result is the maximum-product of the array. For an odd number of negative values there are two possible cases:
The array contains only a single negative value: In that case either the subarray with all values with smaller index than the negative value or the subarray with all values with larger index than the negative value becomes the subarray with the maximum-value
The array contains at least 3 negative values: In that case we have to eliminate either the first negative number and all of it's predecessors, or the last negative number and all of it's successors.
Now let's have a look at the code:
max = Math.Max(nums[i] , Math.Max(prev_max * nums[i] , prev_min * nums[i]));
min = Math.Min(nums[i] , Math.Min(prev_max * nums[i] , prev_min * nums[i]));
Case 1: the evaluation of min is actually irrelevant, since the sign of the product of the array will only flip once, for the negative value. As soon as the negative number is encountered (= nums[i]), max will be nums[i], since both max and min are at least 1 and thus multiplication with nums[i] results in a number <= nums[i]. And for the first number after the negative number nums[i + 1], max will be nums[i + 1] again. Since the so far found maximum is made persistent in result (result = Math.Max(result, max);) after each step, this will automatically result in the correct result for that array.
arr: 2 3 2 -4 4 5
result: 2 6 12 12 12 20
max: 2 6 12 -4 4 20
//Omitted min, since it's irrelevant here.
Case 2: Here min becomes relevant too. Before we encounter the first negative value, min is the smallest number encountered so far in the array. After we encounter the first positive element in the array, the value turns negative. We continue to build both products (min and max) and swap them each time a negative value is encountered and keep updating result. When the last negative value of the array is encountered, result will hold the value of the subarray that eliminates the last negative value and it's successor. After the last negative value, max will be the product of the subarray that eliminates the first negative value and it's predecessors and min becomes irrelevant. Now we simply continue to multiply max with the remaining values in the array and update result until the end of the array is reached.
arr: 2 3 -4 3 -2 5 -6 3
result: 2 6 6 6 144 770 770 770
min: 2 6 -24 -72 -6 -30 -4620 ...
max: 2 6 -4 3 144 770 180 540
//min becomes irrelevant after the last negative value
Putting the pieces together
Since min and max are reset every time we encounter a 0, we can easily reuse them for each subarray that doesn't contain a 0. Thus Rule 1 is applied implicitly without interfering with Rule 2. Since result isn't reset each time a new subarray is inspected, the value will be kept persistent over all runs. Thus this algorithm works.
Hope this is understandable (To be honest, I doubt it and will try to improve the answer, if any questions appear). Sry for that monstrous answer.
Lets take assume the contiguous subarray, which produces the maximal product, is a[i], a[i+1], ..., a[j]. Since it is the array with the largest product, it is also the one suffix of a[0], a[1], ..., a[j], that produces the largest product.
The idea of your given algorithm is the following: For every prefix-array a[0], ..., a[j] find the largest suffix array. Out of these suffix arrays, take the maximal.
At the beginning, the smallest and biggest suffix-product are simply nums[0]. Then it iterates over all other numbers in the array. The largest suffix-array is always build in one of three ways. It's just the last numbers nums[i], it's the largest suffix-product of the shortened list multiplied by the last number (if nums[i] > 0), or it's the smallest (< 0) suffix-product multiplied by the last number (if nums[i] < 0). (*)
Using the helper variable result, you store the maximal such suffix-product you found so far.
(*) This fact is quite easy to proof. If you have a different case, for instance there exists a different suffix-product that produces a bigger number, than together with the last number nums[i] you create an even bigger suffix, which would be a contradiction.

Neighboring gray-level dependence matrix (NGLDM) in MATLAB

I would like to calculate a couple of texture features (namely: small/ large number emphasis, number non-uniformity, second moment and entropy). Those can be computed from Neighboring gray-level dependence matrix. I'm struggling with understanding/implementation of this. There is very little info on this method (publicly available).
According to this paper:
This matrix takes the form of a two-dimensional array Q, where Q(i,j) can be considered as frequency counts of grayness variation of a processed image. It has a similar meaning as histogram of an image. This array is Ng×Nr where Ng is the number of possible gray levels and Nr is the number of possible neighbours to a pixel in an image.
If the image function f(i,j) is discrete, then it is easy to computer the Q matrix (for positive integer d, a) by counting the number of times the difference between each element in f(i,j) and its neighbours is equal or less than a at a certain distance d.
Here is the example from the same paper (d = 1, a = 0):
Input (image) matrix and output matrix Q:
I've been looking at this example for hours now and still can't figure out how they got that Q matrix. Anyone?
The method was originally created by C. Sun and W. Wee and was described in a paper called: "Neighboring gray level dependence matrix for texture classification" to which I got access, but can't download (after pressing download the page reloads and that's it).
In the example that you have provided, d=1 and a=0. When d=1, we consider pixels in an 8-pixel neighbourhood. When a=0, this means that we look for pixels that have the same value as the centre of the neighbourhood.
The basic algorithm is the following:
Initialize your NGLDM matrix to all zeroes. The total number of rows corresponds to the total number of possible intensities / values in your image. The total number of columns corresponds to how many pixels are in your neighbourhood plus 1. As such for d=1, we have an 8-pixel neighbourhood and so 8 + 1 = 9. Because there are 4 possible intensities (0,1,2,3), we thus have a 4 x 9 matrix. Let's call this matrix M.
For each pixel in your matrix, take note of this pixel. This goes in the Ng row.
Write out how many valid neighbours there are that surround this pixel.
Count how many times you see the neighbouring pixels matching that pixel in Step #1. This is your Nr column.
Once you figure out the numbers in Step #1 and Step #2, increment this location by 1.
Here's a slight gotcha: They ignore the border locations. As such, you don't do this procedure for the first row, last row, first column or last column. My guess is that they want to be sure that you have an 8-pixel neighbourhood all the time. This is also dictated by the distance d=1. You must be able to grab every valid pixel given a centre location at d=1. If d=2, then you would have to make sure that every pixel in the centre of the neighbourhood has a 25 pixel neighbourhood and so on.
Let's start from the second row, second column location of this matrix. Let's go through the steps:
Ng = 1 as the location is 1.
Valid neighbours - Starting from the top left pixel in this neighbourhood, and scanning left to right and omitting the centre, we have: 1, 1, 2, 0, 1, 0, 2, 2.
How many values are equal to 1? Three times. Therefore Nr = 3
M(Ng,Nr) += 1. Access row Ng = 1, and access row Nr = 3, and increment this spot by 1.
Want to know how I figured out they don't count the borders? Let's do the bottom left pixel. That location is 0, so Ng = 0. If you repeat the algorithm that I just said, you would expect Ng = 0, Nr = 1, and so you would expect at least one entry in that location in your matrix... but you don't! If you do similar checks around the border of the image, you'll see that entries that are supposed to be there... aren't. Take a look at the third row, fifth column. You would think that Ng = 1 and Nr = 1, but we don't see that in the matrix.
One more example. Why is M(Ng,Nr) = 4, Ng = 2, Nr = 4? Well, take a look at every pixel that has a 2 in it. The only valid locations where we can capture an 8 pixel neighbourhood successfully are the row=2, col=4, row=3, col=3, row=3, col=4, row=4, col=3, and row=4, col=4. By applying the same algorithm that we have seen, you'll see that for each of those locations, Nr = 4. As such, we see this combination of Ng = 2, Nr = 4 four times, and that's why the location is set to 4. However, in row=3, col=4, this actually is Nr = 5, as there are five 2s in that neighbourhood at that centre. That's why you see Ng = 2, Nr = 5, M(Ng,Nr) = 1.
As an example, let's do one of the locations. Let's do the 2 smack dab in the middle of the matrix (row=3, col=3):
Ng = 2
What are the valid neighbouring pixels? 1, 1, 2, 0, 2, 3, 2, 2 (omit the centre)
Count how many pixels equal to 2. There are four of them, so Nr = 4
M(Ng,Nr) += 1. Take Ng = 2, Nr = 4 and increment this spot by 1.
If you do this with the other valid locations that have 2, you'll see that Nr = 4 each time with the exception of the third row and fourth column, where Nr = 5.
So how would we implement this in MATLAB? What you can do is use im2col to transform each valid neighbourhood into columns. What I'm also going to do is extract the centre of each neighbourhood. This is actually the middle row of the matrix. We will then figure out how many pixels for each neighbourhood equal the centre, sum them up, and this will determine our Nr values. The Ng values will be the middle row values themselves. Once we do this, we can compute a histogram based on these values just like how the algorithm is doing to get our matrix. In other words, try doing this:
% // Your example
A = [1 1 2 3 1; 0 1 1 2 2; 0 0 2 2 1; 3 3 2 2 1; 0 0 2 0 1];
B = im2col(A, [3 3]); %//Convert neighbourhoods to columns - 3 x 3 means d = 1
C = bsxfun(#eq, B, B(5,:)); %//Figure out a logical matrix where each column tells
%//you how many elements equals the one in each centre
D = sum(C, 1) - 1; %// Must subtract by 1 to discount centre pixel
Ng = B(5,:).' + 1; % // We must make this into a column vector, and we also must
% // offset by 1 as MATLAB starts indexing by 1.
%// Column vector is for accumarray input
Nr = D.' + 1; %// Do the same for Nr. We could have simply left out the + 1 here and
%// took out the subtraction of -1 for D, but I want to explicitly show
%// the steps
Q = accumarray([Ng Nr], 1, [4 9]); %// 4 unique intensities, 9 possible locations (0-8)
... and here is our matrix:
Q =
0 0 1 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0
0 0 0 0 4 1 0 0 0
0 1 0 0 0 0 0 0 0
If you check this, you'll see this matches with Q.
Bonus
If you want to be able to accommodate for the algorithm in general, where you specify d and a, we can simply follow the guidelines of your text. For each neighbourhood, you find the difference between the centre pixel and all of the other pixels. You count how many pixels are <= a for any positive integer d. Note that this will create a 2*d + 1 x 2*d + 1 neighbourhood we need to examine. We can also make this into a function. Without further ado:
%// Set A up yourself, then use a and d as inputs
%// Precondition - a and d are both integers. a can be 0 and d is positive!
function [Q] = calculateGrayDepMatrix(A, a, d)
neigh = 2*d + 1; % //Calculate rows/columns of neighbourhood
numTotalNeigh = neigh*neigh; % //Calculate total number of pixels in neighbourhood
middleRow = ceil(numTotalNeigh / 2); %// Figure out which index the middle row is
B = im2col(A, [neigh neigh]); %// Make into columns
Cdiff = abs(bsxfun(#minus, B, B(middleRow,:))); %// For each neighbourhood, subtract with its centre
C = Cdiff <= a; %// For each neighbourhood, figure out which differences are <= a
D = sum(C, 1) - 1; % //For each neighbourhood, add them up
Ng = B(middleRow,:).' + 1; % // Determine Ng and Nr, and find Q
Nr = D.' + 1;
Q = accumarray([Ng Nr], 1, [max(Ng) numTotalNeigh]);
end
We can recreate the scenario we showed above with the example matrix by:
A = [1 1 2 3 1; 0 1 1 2 2; 0 0 2 2 1; 3 3 2 2 1; 0 0 2 0 1];
Q = calculateGrayDepMatrix(A, 0, 1);
Q is thus:
Q =
0 0 1 0 0 0 0 0 0
0 0 1 1 0 0 0 0 0
0 0 0 0 4 1 0 0 0
0 1 0 0 0 0 0 0 0
Hope this helps!

Given an integer N and a set of operations, reduce N to 1 in the least amount of steps

On a given integer N we can use the following operations:
If N can be divided by 3: divide by 3.
If N can be divided by 2: divide by 2.
Subtract 1.
How can I find a strategy to reach 1 in the least number of steps?
As mbeckish mentioned you can treat this as a BFS traversal, which has significantly better time and space complexity than a bottom up DP approach. You can also apply a branch and bound (B&B) heuristic of sorts in the traversal such that you prune the branches of the tree at nodes that we've already seen the labeled value before. Unlike an actual B&B heuristic, this will not prune off the optimal solution since it does not involve any educated guesses of where the optimal solution might be. I'll give a visual example and have the algorithm reduce down to 0 to better illustrate.
Here is a full tree of operations reducing 10 to 0:
--------10---------
5 -----9----
---4--- -3- ------8------
2 -3- 1 2 --4-- 7
1 1 2 0 1 2 -3- -----6------
0 0 1 0 1 1 2 2 -3- 5
0 0 0 1 1 1 2 --4--
0 0 0 1 2 -3-
0 1 1 2
0 0 1
0
Since we're doing BFS, we'll actually stop at the first zero like follows and not build the deeper parts of the tree:
--------10------
5 -----9--------
---4--- -3- ------8------
2 -3- 1 2 4 7
1 1 2 0
However we can reduce the number of branches further by the B&B heuristic to look like this (and this makes a huge difference on massive numbers):
--------10------
5 -----9--------
4 3 8
2 1 7
0
Time Complexity: O(log n) Space Complexity: O(log n) (I think)
Below is python 3 code with input of 1 googol (10^100) which takes about 8 seconds to run on my computer and around ~350 MB of RAM. You can also run it online at https://repl.it/B3Oq/76
from collections import deque
def number_of_steps(i):
Q = deque()
seen_before = set()
steps = 0
Q.append((i, steps))
while True:
j, steps = Q.popleft()
if j == 1:
return steps
if j % 3 == 0:
branch(Q, seen_before, steps, j // 3)
if j % 2 == 0:
branch(Q, seen_before, steps, j // 2)
branch(Q, seen_before, steps, j - 1)
def branch(Q, seen_before, steps, k):
if k not in seen_before:
seen_before.add(k)
Q.append((k, steps + 1))
import time
n = 10**100
print('input:', n)
start = time.time()
steps = number_of_steps(n)
end = time.time()
print('runtime (seconds):', end - start)
print('number of steps:', steps)
There is fast dynamic programming solution :-
minSteps(N) = Minimum(minSteps(N/3),minSteps(N/2),minSteps(N-1)) + 1
Note: If N is not divisible by 3 or 2 then dont include it in the DP equation.
Time Complexity : O(N)
Space Complexity : O(N)
Java Code for DP solution :-
public static int decompose(int n) {
int steps [] = new int[n+1];
steps[1] = 0;
for(int i=2;i<=n;i++) {
int min = n;
if(i%2==0) {
min = Math.min(min,steps[i/2]);
}
if(i%3==0) {
min = Math.min(min,steps[i/3]);
}
min = Math.min(min,steps[i-1]);
steps[i] = min + 1;
}
int k =n;
System.out.println("Steps:");
while(k>1) {
if(k%3==0&&steps[k/3]+1==steps[k]) {
System.out.println("div 3");
k=k/3;
}
else if(n%2==0&&steps[k/2]+1==steps[k]) {
System.out.println("div 2");
k=k/2;
}
else {
System.out.println("minus 1");
k=k-1;
}
}
return(steps[n]);
}
Treat this as a breadth-first tree traversal.
The root node is N. The operations are the edges that lead to its children,
Stop when you reach a 1.
The path from the root to the 1 is the solution.

Finding maximum size sub-matrix of all 1's in a matrix having 1's and 0's

Suppose you are given an mXn bitmap, represented by an array M[1..m,1.. n] whose entries are all 0 or 1. A all-one block is a subarray of the form M[i .. i0, j .. j0] in which every bit is equal to 1. Describe and analyze an efficient algorithm to find an all-one block in M with maximum area
I am trying to make a dynamic programming solution. But my recursive algorithm runs in O(n^n) time, and even after memoization I cannot think of bringing it down below O(n^4). Can someone help me find a more efficient solution?
An O(N) (number of elements) solution:
A
1 1 0 0 1 0
0 1 1 1 1 1
1 1 1 1 1 0
0 0 1 1 0 0
Generate an array C where each element represents the number of 1s above and including it, up until the first 0.
C
1 1 0 0 1 0
0 2 1 1 2 1
1 3 2 2 3 0
0 0 3 3 0 0
We want to find the row R, and left, right indices l , r that maximizes (r-l+1)*min(C[R][l..r]). Here is an algorithm to inspect each row in O(cols) time:
Maintain a stack of pairs (h, i), where C[R][i-1] < h ≤ C[R][i]. At any position cur, we should have h=min(C[R][i..cur]) for all pairs (h, i) on the stack.
For each element:
If h_cur>h_top
Push (h, i).
Else:
While h_cur<h_top:
Pop the top of the stack.
Check whether it would make a new best, i.e. (i_cur-i_pop)*h_pop > best.
If h_cur>h_top
Push (h, i_lastpopped).
An example of this in execution for the third row in our example:
i =0 1 2 3 4 5
C[i]=1 3 2 2 3 0
(3, 4)
S= (3, 1) (2, 1) (2, 1) (2, 1)
(1, 0) (1, 0) (1, 0) (1, 0) (1, 0)
(0,-1) (0,-1) (0,-1) (0,-1) (0,-1) (0,-1)
i=0, C[i]=1) Push (1, 0).
i=1, C[i]=3) Push (3, 1).
i=2, C[i]=2) Pop (3, 1). Check whether (2-1)*3=3 is a new best.
        The last i popped was 1, so push (2, 1).
i=3, C[i]=2) h_cur=h_top so do nothing.
i=4, C[i]=3) Push (3, 4).
i=5, C[i]=0) Pop (3, 4). Check whether (5-4)*3=3 is a new best.
        Pop (2, 1). Check whether (5-1)*2=8 is a new best.
        Pop (1, 0). Check whether (5-0)*1=5 is a new best.
        End. (Okay, we should probably add an extra term C[cols]=0 on the end for good measure).
Here's an O(numCols*numLines^2) algorithm. Let S[i][j] = sum of the first i elements of column j.
I will work the algorithm on this example:
M
1 1 0 0 1 0
0 1 1 1 0 1
1 1 1 1 0 0
0 0 1 1 0 0
We have:
S
1 1 0 0 1 0
1 2 1 1 1 1
2 3 2 2 1 1
2 3 3 3 1 1
Now consider the problem of finding the maximum subarray of all ones in a one-dimensional array. This can be solved using this simple algorithm:
append 0 to the end of your array
max = 0, temp = 0
for i = 1 to array.size do
if array[i] = 1 then
++temp
else
if temp > max then
max = temp
temp = 0
For example, if you have this 1d array:
1 2 3 4 5 6
1 1 0 1 1 1
you'd do this:
First append a 0:
1 2 3 4 5 6 7
1 1 0 1 1 1 0
Now, notice that whenever you hit a 0, you know where a sequence of contiguous ones ends. Therefore, if you keep a running total (temp variable) of the current number of ones, you can compare that total with the maximum so far (max variable) when you hit a zero, and then reset the running total. This will give you the maximum length of a contiguous sequence of ones in the variable max.
Now you can use this subalgorithm to find the solution for your problem. First of all append a 0 column to your matrix. Then compute S.
Then:
max = 0
for i = 1 to M.numLines do
for j = i to M.numLines do
temp = 0
for k = 1 to M.numCols do
if S[j][k] - S[i-1][k] = j - i + 1 then
temp += j - i + 1
else
if temp > max then
max = temp
temp = 0
Basically, for each possible height of a subarray (there are O(numLines^2) possible heights), you find the one with maximum area having that height by applying the algorithm for the one-dimensional array (in O(numCols)).
Consider the following "picture":
M
1 1 0 0 1 0 0
i 0 1 1 1 0 1 0
j 1 1 1 1 0 0 0
0 0 1 1 0 0 0
This means that we have the height j - i + 1 fixed. Now, take all the elements of the matrix that are between i and j inclusively:
0 1 1 1 0 1 0
1 1 1 1 0 0 0
Notice that this resembles the one-dimensional problem. Let's sum the columns and see what we get:
1 2 2 2 0 1 0
Now, the problem is reduced to the one-dimensional case, with the exception that we must find a subsequence of contiguous j - i + 1 (which is 2 in this case) values. This means that each column in our j - i + 1 "window" must be full of ones. We can check for this efficiently by using the S matrix.
To understand how S works, consider a one-dimensional case again: let s[i] = sum of the first i elements of the vector a. Then what is the sum of the subsequence a[i..j]? It's the sum of all the elements up to and including a[j], minus the sum of all those up to and including a[i-1], meaning s[j] - s[i-1]. The 2d case works the same, except we have an s for each column.
I hope this is clear, if you have any more questions please ask.
I don't know if this fits your needs, but I think there's also an O(numLines*numCols) algorithm, based on dynamic programming. I can't figure it out yet, except for the case where the subarray you're after is square. Someone might have better insight however, so wait a bit more.
Define a new matrix A wich will store in A[i,j] two values: the width and the height of the largest submatrix with the left upper corner at i,j, fill this matrix starting from the bottom right corner, by rows bottom to top. You'll find four cases:
Perform these cases when given matrix at [i,j]=1
case 1: none of the right or bottom neighbour elements in the original matrix are equal to the current one, i.e: M[i,j] != M[i+1,j] and M[i,j] != M[i,j+1] being M the original matrix, in this case, the value of A[i,j] is 1x1
case 2: the neighbour element to the right is equal to the current one but the bottom one is different, the value of A[i,j].width is A[i+1,j].width+1 and A[i,j].height=1
case 3: the neighbour element to the bottom is equal but the right one is different, A[i,j].width=1, A[i,j].height=A[i,j+1].height+1
case 4: both neighbours are equal:
Three rectangles are considered:
A[i,j].width=A[i,j+1].width+1; A[i,j].height=1;
A[i,j].height=A[i+1,j].height+1; a[i,j].width=1;
A[i,j].width = min(A[i+1,j].width+1,A[i,j+1].width) and A[i,j].height = min(A[i,j+1]+1,A[i+1,j])
The one with the max area in the above three cases will be considered to represent the rectangle at this position.
The size of the largest matrix that has the upper left corner at i,j is A[i,j].width*A[i,j].height so you can update the max value found while calculating the A[i,j]
the bottom row and the rightmost column elements are treated as if their neighbours to the bottom and to the right respectively are different.
Here is a O(N) implementation in C#.
The idea is to use a dynamic programming to build an accumulated Matrix that has the size of the biggest submatrix including the current cell itself.
public static int LargestSquareMatrixOfOne(int[,] original_mat)
{
int[,] AccumulatedMatrix = new int[original_mat.GetLength(0), original_mat.GetLength(1)];
AccumulatedMatrix[0, 0] = original_mat[0, 0];
int biggestSize = 1;
for (int i = 0; i < original_mat.GetLength(0); i++)
{
for (int j = 0; j < original_mat.GetLength(1); j++)
{
if (i > 0 && j > 0)
{
if (original_mat[i, j] == 1)
{
AccumulatedMatrix[i, j] = Math.Min(AccumulatedMatrix[i - 1, j - 1], (Math.Min(AccumulatedMatrix[i - 1, j], AccumulatedMatrix[i, j - 1]))) + 1;
if (AccumulatedMatrix[i, j] > biggestSize)
{
biggestSize = AccumulatedMatrix[i, j];
}
}
else
{
AccumulatedMatrix[i, j] = 0;
}
}
else if ( (i > 0 && j == 0) || (j > 0 && i == 0))
{
if (original_mat[i, j] == 1) { AccumulatedMatrix[i, j] = 1; }
else { AccumulatedMatrix[i, j] = 0; }
}
}
}
return biggestSize;
}

Resources