Matrix construction algorithm - algorithm

I have a small question related to optimization. I have a json, in which an array of elements describing the path, i.e. from the first one can rise to the second, from it to the right to the third, and so on.
[
{
"number": 1,
"upperLevel": 2
},
{
"number": 2,
"rightLevel": 3,
"leftLevel": 4
},
{
"number": 3,
"lowerLevel": 6
},
{
"number": 4,
"upperLevel": 5
},
{
"number": 5
},
{
"number": 6,
"lowerLevel": 7
},
{
"number": 7
}
]
These paths can be different.
I need to build a matrix out of this.
5 0 0
4 2 3
0 1 6
0 0 7
The problem is that the elements do not have an exact position where they are on the matrix, and it is not clear where to initially place the first element, so as not to go beyond the size of the array later. To avoid this, I specify the size twice as large as the number of elements, and put the first one in the center, so that wherever the path goes, it does not go beyond the boundaries.This is what my algorithm looks like.
val matrix = buildMatrix(
levels = data.map { it.number to it }.toMap(),
matrix = MutableList(data.size*2) { MutableList<Level?>(data.size*2) { null } },
obj = data.first(),
processedLevel = mutableSetOf(),
x = data.size,
y = data.size
)
matrix.reverse()
There is a bit of recursion here.
private fun buildMatrix(
levels: Map<Int, Level>,
matrix: MutableList<MutableList<Level?>>,
obj: Level,
processedLevel: MutableSet<Int>,
x: Int,
y: Int
): MutableList<MutableList<Level?>>{
if(processedLevel.contains(obj.number)) return matrix
matrix[y][x] = obj
processedLevel.add(obj.number)
if(obj.upperLevel != null) levels[obj.upperLevel]?.let { buildMatrix(levels, matrix, it, processedLevel, x, y+1) }
if(obj.rightLevel != null) levels[obj.rightLevel]?.let { buildMatrix(levels, matrix, it, processedLevel, x+1, y) }
if(obj.lowerLevel != null) levels[obj.lowerLevel]?.let { buildMatrix(levels, matrix, it, processedLevel, x, y-1) }
if(obj.leftLevel != null) levels[obj.leftLevel]?.let { buildMatrix(levels, matrix, it, processedLevel, x-1, y) }
return matrix
}
But in this case, there are many empty values. And the more elements there are in json, the more empty spaces there will be.
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 5 0 0 0 0 0 0 0
0 0 0 0 0 0 4 2 3 0 0 0 0 0
0 0 0 0 0 0 0 1 6 0 0 0 0 0
0 0 0 0 0 0 0 0 7 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
If someone needs it, then I display the matrix like this. println(matrix.reversed().joinToString("\n") { row -> row.map { it?.number ?: 0 }.joinToString(" ") })
To remove these blank lines, I wrote a function like this.
private fun removeEmptyLines(matrix: MutableList<MutableList<Level?>>): MutableList<MutableList<Level?>>{
matrix.removeIf { row ->
row.all { it == null }
}
val indexForRemove = mutableSetOf<Int>()
matrix.first().forEachIndexed { index, _ ->
if(matrix.all { it[index] == null }) indexForRemove.add(index)
}
indexForRemove.sortedDescending().forEach { index ->
matrix.forEach { it.removeAt(index) }
}
return matrix
}
And as a result, the result was obtained, which I described above, but it seems to me that this is not an ideal option, maybe someone has ideas on how this can be optimized? Thank you in advance.

You could first collect the coordinates of each position in a Map. That will allow you to start at any arbitrary coordinate and have negative coordinates. Then use the Map to find the minimal sized 2D array needed and populate it.
fun buildMatrix(data: List<Level>): List<List<Level?>> {
class Point(val x: Int, val y: Int)
val remaining = data.toMutableList()
val points = mutableMapOf(1 to Point(0, 0))
while (remaining.isNotEmpty()) {
val level = remaining.firstOrNull { it.number in points } ?: error("Invalid input data")
remaining.remove(level)
val point = points[level.number]!!
level.upperLevel?.let { points[it.number] = Point(point.x, point.y + 1) }
level.lowerLevel?.let { points[it.number] = Point(point.x, point.y - 1) }
level.leftLevel?.let { points[it.number] = Point(point.x - 1, point.y) }
level.rightLevel?.let { points[it.number] = Point(point.x + 1, point.y) }
}
val xOffset = -points.values.minBy(Point::x)!!.x
val yOffset = -points.values.minBy(Point::y)!!.y
val xMax = points.values.maxBy(Point::x)!!.x + xOffset
val yMax = points.values.maxBy(Point::y)!!.y + yOffset
val matrix = Array(yMax + 1) { arrayOfNulls<Level>(xMax + 1) }
for ((number, point) in points) {
matrix[point.y + yOffset][point.x + xOffset] = data.find { it.number == number }
}
return matrix.map(Array<Level?>::toList)
}

First of All change your json input to cover two type of information:
upperLevel, leftLevel.
So your input will change to this :
[
{
"number": 1,
"upperLevel": 2
},
{
"number": 2,
"leftLevel": 4
},
{
"number": 3,
"leftLevel": 2
},
{
"number": 4,
"upperLevel": 5
},
{
"number": 5
},
{
"number": 6,
"upperLevel": 3
},
{
"number": 7
"upperLevel": 6
}
]
Now every input has a tuple of index based on x(row) and y(column). When an element has an upperLevel the X coordinate will increase by 1 and y coordinate is equal to upper level. For example i1=(x2+1,y2) because the 1 is below the 2.
So final indexes will be as below:
i1=(x2+1,y2)
i2=(x4,y4+1)
i3=(x2,y2+1)
i4=(x5+1,y5)
i5=(0,0)
i6=(x3+1,y3)
i7=(x6+1,y6)
Since number 5 has no information we set it as (0,0) which is stop point for recursive function.
Now replace x5=0,y5=0 in the indexes and you will have:
i1=(x2+1,y2) = (2,1)
i2=(x4,y4+1) = (1,1)
i3=(x2,y2+1) = (1,2)
i4=(x5+1,y5) = (1,0)
i5=(0,0)
i6=(x3+1,y3) = (2,2)
i7=(x6+1,y6) = (3,2)
Please feel free to ask questions in comment.

Related

How to calculate cost to Convert an N X M binary matrix to all 0 matrix with only allowed moves as square-matrix toggle?

Given an N X M binary matrix ( every element is either 1 or 0) , find the minimum number of moves to convert it to an all 0 matrix.
For converting a matrix, one can choose squares of any size and convert the value of that square. '1' changes to '0' and '0' changes to '1'.This process can be done multiple times with square of the same size. Converting any square counts as 1 move.
Calculate minimum number of moves required..
Example :
input matrix
0 1 1
0 0 0
0 1 1
we need to calculate minimum moves to convert this to all '0' matrix
0 0 0
0 0 0
0 0 0
Here,
For square of size 1 ( 1 X 1 or single element sub-matrix), the total number of moves required to convert this matrix is 4 . he converts elements for position (1,2),(1,3),(3,2),(3,3)
For square of size 2 ( 2 X 2 or single element sub-matrix), it takes 2 moves to convert the matrix
First we can convert elements from (1,2) to (2,3) and the matrix becomes, {{0 0 0}, {0 1 1}, {0 1 1}}
And then we convert elements from (2,2)to (3,3) and the matrix becomes ``{{0 0 0}, {0 0 0}, {0 0 0}}```
So minimum is 2.
Could some help in designing an approach to this ?
I attempted to solve it using Gaussian elimination for every possible square size. But the result is not correct here. There must be some gap in my approach to this problem.
package com.practice.hustle;
import java.util.Arrays;
public class GaussianElimination {
public static void main(String[] args) {
int countMoves = Integer.MAX_VALUE;
byte[][] inputMatrix = new byte[3][3];
inputMatrix[0][0] = 0;
inputMatrix[0][1] = 1;
inputMatrix[0][2] = 1;
inputMatrix[1][0] = 0;
inputMatrix[1][1] = 0;
inputMatrix[1][2] = 0;
inputMatrix[2][0] = 0;
inputMatrix[2][1] = 1;
inputMatrix[2][2] = 1;
int N = inputMatrix.length;
int M = inputMatrix[0].length;
int maxSize = Math.min(N, M);
for (int j = 2; j <= maxSize; ++j) { // loop for every possible square size
byte[][] a = new byte[N * M][(N * M) + 1];
for (int i = 0; i < N * M; i++) { // logic for square wise toggle for every element of N*M elements
byte seq[] = new byte[N * M + 1];
int index_i = i / M;
int index_j = i % M;
if (index_i <= N - j && index_j <= M - j) {
for (int c = 0; c < j; c++) {
for (int k = 0; k < j; k++) {
seq[i + k + M * c] = 1;
}
}
a[i] = seq;
} else {
if (index_i > N - j) {
seq = Arrays.copyOf(a[i - M], N * M + 1);
} else {
seq = Arrays.copyOf(a[i - 1], N * M + 1);
}
}
seq[N * M] = inputMatrix[index_i][index_j];
a[i] = seq;
}
System.out.println("\nSolving for square size = " + j);
print(a, N * M);
int movesPerSquareSize = gaussian(a);
if (movesPerSquareSize != 0) { // to calculate minimum moves
countMoves = Math.min(countMoves, movesPerSquareSize);
}
}
System.out.println(countMoves);
}
public static int gaussian(byte a[][]) {
// n X n+1 matrix
int N = a.length;
for (int k = 0; k < N - 1; k++) {
// Finding pivot element
int max_i = k, max_value = a[k][k];
for (int i = k + 1; i < N; i++) {
if (a[i][k] > max_value) {
max_value = a[i][k];
max_i = i;
}
}
// swap max row with kth row
byte[] temp = a[k];
a[k] = a[max_i];
a[max_i] = temp;
// convert to 0 all cells below pivot in the column
for (int i = k+1; i < N; i++) {
// int scalar = a[i][k] + a[k][k]; // probability of a divide by zero
if (a[i][k] == 1) {
for (int j = 0; j <= N; j++) {
if (a[i][j] == a[k][j]) {
a[i][j] = 0;
} else {
a[i][j] = 1;
}
}
}
}
}
System.out.println("\n\tAfter applying gaussian elimination : ");
print(a, N);
int count = 0;
for (int i = 0; i < N; i++) {
if (a[i][N] == 1)
++count;
}
return count;
}
private static void print(byte[][] a, int N) {
for (int i = 0; i < N; i++) {
System.out.print("\t ");
for (int j = 0; j < N + 1; j++) {
System.out.print(a[i][j] + " ");
}
System.out.println(" ");
}
}
}
Its giving final reduced Euler matrix formed is incorrect and thereby the result is also incorrect.
I think its failing due to the logic used for element like - the cell at index-(2,3) , for that we are not sure which square would it be a part of ( either the square from (1,2) to (2,3) or the square from ( 2,2) to (3,3))
here the input matrix to Gaussian algo is having exactly same sequence at 2nd and 3rd row which could be the culprit of incorrect results.
1 1 0 1 1 0 0 0 0 0
* 0 1 1 0 1 1 0 0 0 1 *
* 0 1 1 0 1 1 0 0 0 1 *
0 0 0 1 1 0 1 1 0 0
0 0 0 0 1 1 0 1 1 0
0 0 0 0 1 1 0 1 1 0
0 0 0 1 1 0 1 1 0 0
0 0 0 0 1 1 0 1 1 1
0 0 0 0 1 1 0 1 1 1
for a sqaure size 2, the above program prints :
Solving for square size = 2
The input to Gaussian algo :
1 1 0 1 1 0 0 0 0 0
0 1 1 0 1 1 0 0 0 1
0 1 1 0 1 1 0 0 0 1
0 0 0 1 1 0 1 1 0 0
0 0 0 0 1 1 0 1 1 0
0 0 0 0 1 1 0 1 1 0
0 0 0 1 1 0 1 1 0 0
0 0 0 0 1 1 0 1 1 1
0 0 0 0 1 1 0 1 1 1
After applying gaussian elimination :
1 0 1 0 0 0 1 0 1 1
0 1 1 0 0 0 0 1 1 0
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 1 0 1 0
0 0 0 0 1 1 0 1 1 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 1

Finding islands of ones with zeros boundary

I am trying to find islands of numbers in a matrix.
By an island, I mean a rectangular area where ones are connected with each other either horizontally, vertically or diagonally including the boundary layer of zeros
Suppose I have this matrix:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1
0 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 0
0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1
0 0 0 1 0 1 0 1 1 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 0 1 1 1 0 0 0 0 0 0 0
0 0 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
By boundary layer, I mean row 2 and 7, and column 3 and 10 for island#1.
This is shown below:
I want the row and column indices of the islands. So for the above matrix, the desired output is:
isl{1}= {[2 3 4 5 6 7]; % row indices of island#1
[3 4 5 6 7 8 9 10]} % column indices of island#1
isl{2}= {[2 3 4 5 6 7]; % row indices of island#2
[12 13 14 15 16 17]}; % column indices of island#2
isl{3} ={[9 10 11 12]; % row indices of island#3
[2 3 4 5 6 7 8 9 10 11];} % column indices of island#3
It doesn't matter which island is detected first.
While I know that the [r,c] = find(matrix) function can give the row and column indices of ones but I have no clues on how to detect the connected ones since they can be connected in horizontal, vertical and diagonal order.
Any ideas on how to deal with this problem?
You should look at the BoundingBox and ConvexHull stats returned by regionprops:
a = imread('circlesBrightDark.png');
bw = a < 100;
s = regionprops('table',bw,'BoundingBox','ConvexHull')
https://www.mathworks.com/help/images/ref/regionprops.html
Finding the connected components and their bounding boxes is the easy part. The more difficult part is merging the bounding boxes into islands.
Bounding Boxes
First the easy part.
function bBoxes = getIslandBoxes(lMap)
% find bounding box of each candidate island
% lMap is a logical matrix containing zero or more connected components
bw = bwlabel(lMap); % label connected components in logical matrix
bBoxes = struct2cell(regionprops(bw, 'BoundingBox')); % get bounding boxes
bBoxes = cellfun(#round, bBoxes, 'UniformOutput', false); % round values
end
The values are rounded because the bounding boxes returned by regionprops lies outside its respective component on the grid lines rather than the cell center, and we need integer values to use as subscripts into the matrix. For example, a component that looks like this:
0 0 0
0 1 0
0 0 0
will have a bounding box of
[ 1.5000 1.5000 1.0000 1.0000 ]
which we round to
[ 2 2 1 1]
Merging
Now the hard part. First, the merge condition:
We merge bounding box b2 into bounding box b1 if b2 and the island of b1 (including the boundary layer) have a non-null intersection.
This condition ensures that bounding boxes are merged when one component is wholly or partially inside the bounding box of another, but it also catches the edge cases when a bounding box is within the zero boundary of another. Once all of the bounding boxes are merged, they are guaranteed to have a boundary of all zeros (or border the edge of the matrix), otherwise the nonzero value in its boundary would have been merged.
Since merging involves deleting the merged bounding box, the loops are done backwards so that we don't end up indexing non-existent array elements.
Unfortunately, making one pass through the array comparing each element to all the others is insufficient to catch all cases. To signal that all of the possible bounding boxes have been merged into islands, we use a flag called anyMerged and loop until we get through one complete iteration without merging anything.
function mBoxes = mergeBoxes(bBoxes)
% find bounding boxes that intersect, and merge them
mBoxes = bBoxes;
% merge bounding boxes that overlap
anyMerged = true; % flag to show when we've finished
while (anyMerged)
anyMerged = false; % no boxes merged on this iteration so far...
for box1 = numel(mBoxes):-1:2
for box2 = box1-1:-1:1
% if intersection between bounding boxes is > 0, merge
% the size of box1 is increased b y 1 on all sides...
% this is so that components that lie within the borders
% of another component, but not inside the bounding box,
% are merged
if (rectint(mBoxes{box1} + [-1 -1 2 2], mBoxes{box2}) > 0)
coords1 = rect2corners(mBoxes{box1});
coords2 = rect2corners(mBoxes{box2});
minX = min(coords1(1), coords2(1));
minY = min(coords1(2), coords2(2));
maxX = max(coords1(3), coords2(3));
maxY = max(coords1(4), coords2(4));
mBoxes{box2} = [minX, minY, maxX-minX+1, maxY-minY+1]; % merge
mBoxes(box1) = []; % delete redundant bounding box
anyMerged = true; % bounding boxes merged: loop again
break;
end
end
end
end
end
The merge function uses a small utility function that converts rectangles with the format [x y width height] to a vector of subscripts for the top-left, bottom-right corners [x1 y1 x2 y2]. (This was actually used in another function to check that an island had a zero border, but as discussed above, this check is unnecessary.)
function corners = rect2corners(rect)
% change from rect = x, y, width, height
% to corners = x1, y1, x2, y2
corners = [rect(1), ...
rect(2), ...
rect(1) + rect(3) - 1, ...
rect(2) + rect(4) - 1];
end
Output Formatting and Driver Function
The return value from mergeBoxes is a cell array of rectangle objects. If you find this format useful, you can stop here, but it's easy to get to the format requested with ranges of rows and columns for each island:
function rRanges = rect2range(bBoxes, mSize)
% convert rect = x, y, width, height to
% range = y:y+height-1; x:x+width-1
% and expand range by 1 in all 4 directions to include zero border,
% making sure to stay within borders of original matrix
rangeFun = #(rect) {max(rect(2)-1,1):min(rect(2)+rect(4),mSize(1));...
max(rect(1)-1,1):min(rect(1)+rect(3),mSize(2))};
rRanges = cellfun(rangeFun, bBoxes, 'UniformOutput', false);
end
All that's left is a main function to tie all of the others together and we're done.
function theIslands = getIslandRects(m)
% get rectangle around each component in map
lMap = logical(m);
% get the bounding boxes of candidate islands
bBoxes = getIslandBoxes(lMap);
% merge bounding boxes that overlap
bBoxes = mergeBoxes(bBoxes);
% convert bounding boxes to row/column ranges
theIslands = rect2range(bBoxes, size(lMap));
end
Here's a run using the sample matrix given in the question:
M =
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1
0 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 0
0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1
0 0 0 1 0 1 0 1 1 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 0 1 1 1 0 0 0 0 0 0 0
0 0 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
>> getIslandRects(M)
ans =
{
[1,1] =
{
[1,1] =
9 10 11 12
[2,1] =
2 3 4 5 6 7 8 9 10 11
}
[1,2] =
{
[1,1] =
2 3 4 5 6 7
[2,1] =
3 4 5 6 7 8 9 10
}
[1,3] =
{
[1,1] =
2 3 4 5 6 7
[2,1] =
12 13 14 15 16 17
}
}
Quite easy!
Just use bwboundaries to get the boundaries of each of the blobs. you can then just get the min and max in each x and y direction of each boundary to build your box.
Use image dilation and regionprops
mat = [...
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1;
0 0 0 1 1 1 0 1 1 0 0 0 1 1 1 1 0;
0 0 0 0 0 0 1 0 1 0 0 0 0 1 1 1 1;
0 0 0 1 0 1 0 1 1 0 0 0 1 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 1 0 1 0 1 1 1 0 0 0 0 0 0 0;
0 0 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];
mat=logical(mat);
dil_mat=imdilate(mat,true(2,2)); %here we make bridges to 1 px away ones
l_mat=bwlabel(dil_mat,8);
bb = regionprops(l_mat,'BoundingBox');
bb = struct2cell(bb); bb = cellfun(#(x) fix(x), bb, 'un',0);
isl = cellfun(#(x) {max(1,x(2)):min(x(2)+x(4),size(mat,1)),...
max(1,x(1)):min(x(1)+x(3),size(mat,2))},bb,'un',0);

Algorithm to find and fill enclosed shapes on a grid

So say we have an empty grid of 0s:
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
And you can draw shapes on it. 1 represents a filled cell.
1 1 1 1 0 0 0 0
1 0 0 1 0 0 0 0
1 0 0 1 0 0 0 0
1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0
0 1 1 0 0 1 1 1
1 0 0 1 0 1 0 0
0 1 1 0 0 1 0 0
A shape is considered closed if a four-directional flood-fill algorithm would not leak and fill any cells outside of the shape. A shape can not use the boundary of the grid as one of its sides. So if we filled in all of the closed shapes in this grid with 2s, we would have:
1 1 1 1 0 0 0 0
1 2 2 1 0 0 0 0
1 2 2 1 0 0 0 0
1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0
0 1 1 0 0 1 1 1
1 2 2 1 0 1 0 0
0 1 1 0 0 1 0 0
Implementing the flood-fill algorithm is easy, but I can't figure out a way to (programatically) fill in all enclosed arbitrary shapes in a grid. Are there any type of algorithms or searches I could use for this?
What's wrong with flood-fill algorithm? It is simple end effective with complexity O(N).
At first scan edges for zero values and flood empty regions with mark value 3.
Then walk through inner place. If you find zero cell, flood-fill from this cell with value 2.
(Perhaps you are seeking something like connected-component labeling algorithm. It is intended to mark every connected region by unique mark value)
You can first find zero's which have a path to boundary:
Take arbitrary 0 cell in the boundary, mark it as -1, do this for all of its neighbouring cells recursively (neighbours of neighbours and so on all set to -1). Once none of the boundary cells is zero, turn all zero cells to 2. It means that they are surrounded by only 1's. After all turn all -1's to 0. This is O(n) which n is the number of cells in the grid.
Here is a (lazy) pseudo code, assuming we have n_1xn_2 grid:
function fill()
{
for int i=1..n_1
{
recursivecolor(i,1);
recursivecolor(i,n_2);
}
for int j=1..n_2
{
recursivecolor(1,j);
recursivecolor(n_1,j);
}
for i=1..n_1
for j=1 .. n_2
if (a[i][j] == 0)
a[i][j] = 2;
for i=1..n_1
for j=1 .. n_2
if (a[i][j] == -1)
a[i][j] = 0;
}
function recursivecolor(i,j)
{
if (a[i][j]!=0) return;
a[i][j] = -1;
if (a[i-1][j] == 0)
{
a[i-1][j] = -1;
recursivecolor(i-1,j);
}
// do this for all neighbours of i,j cell
// it also needs check for boundaries, e.g. i-1 should not be zero ...
}

Flood Fill Recursive algorithm

Hello I made use of flood fill recursive algorithm to find the connected cells to each other in an 2D array (Here I am using vectors). But this fails for one boundary test case
#include<iostream>
#include<vector>
using namespace std;
int count = 0;
int max_count = 0;
int min_count = 0;
void floodFillUtil(vector< vector<int> > &a,int i,int j,int m,int n,int prevP,int newN)
{
if (i<0 || i>= m || j<0 || j>=n)
return;
if(a[i][j] != prevP)
return;
count++;
a[i][j] = newN;
floodFillUtil(a,i+1,j+1,m,n,prevP,newN);
floodFillUtil(a,i-1,j-1,m,n,prevP,newN);
floodFillUtil(a,i-1,j+1,m,n,prevP,newN);
floodFillUtil(a,i+1,j-1,m,n,prevP,newN);
floodFillUtil(a,i+1,j,m,n,prevP,newN);
floodFillUtil(a,i,j+1,m,n,prevP,newN);
floodFillUtil(a,i-1,j,m,n,prevP,newN);
floodFillUtil(a,i,j-1,m,n,prevP,newN);
}
void floodFill(vector< vector<int> > &a,int i,int j,int newN,int m,int n) {
int prevP = a[i][j];
floodFillUtil(a,i,j,m,n,prevP,newN);
}
// Driver program to test above function
int main()
{ int m,n;
cin>>m>>n;
vector<vector<int> > a;
vector<int> b;
for(int i=0;i<m;i++)
{for(int j=0;j<n;j++)
{ int temp;
cin>>temp;
b.push_back(temp);
}
a.push_back(b);
b.clear();
}
for(int i=0;i<m;i++)
for(int j=0;j<n;j++) {
if (a[i][j] == 1){
floodFill(a,i,j,2+i,m,m);
min_count = count ;
if(min_count > max_count){
max_count = min_count;
}
count=0;
}
}
for(int i=0;i<m;i++)
{for(int j=0;j<n;j++)
cout<<a[i][j]<<" ";
cout<<endl;}
cout<<max_count;
}
And this is the input test case for which it is failing
8
9
0 1 0 0 0 0 1 1 0
1 1 0 0 1 0 0 0 1
0 0 0 0 1 0 1 0 0
0 1 1 1 0 1 0 1 1
0 1 1 1 0 0 1 1 0
0 1 0 1 1 0 1 1 0
0 1 0 0 1 1 0 1 1
1 0 1 1 1 1 0 0 0
And this is output given by code
0 2 0 0 0 0 2 2 0
2 2 0 0 3 0 0 0 1
0 0 0 0 3 0 3 0 0
0 3 3 3 0 3 0 3 1
0 3 3 3 0 0 3 3 0
0 3 0 3 3 0 3 3 0
0 3 0 0 3 3 0 3 1
3 0 3 3 3 3 0 0 0
27
But the output should be 29, for [1,8] [3,8] and [6,8] it is not changing.What must be the problem in the code.
Looks like a typo here:
floodFill(a,i,j,2+i,m,m);
Should be:
floodFill(a,i,j,2+i,m,n);
Unless your matrix is square. It might be worthwhile to abstract the matrix into an object that knows its own dimensions (see here). Then you can pass fewer parameters everywhere.

construct a matrix in Octave

I have a vector idx = [3; 5; 3; 4; 3; 2; 5; 1]. The number is from 1:k with k = 5. I want to make a "k by m" matrix A (m is the number of elements in the vector idx). Each row of A contains either '0' or '1' with '1' indicated by the index of the vector idx. For example, the third row of A (k = 3) is "1" at columns 1, 3, 5 because those are the indexes of "3" in idx. So that A =
[0 0 0 0 0 0 0 1; 0 0 0 0 1 0 0 0; 1 0 1 0 1 0 0 0; 0 0 0 1 0 0 0 0; 0 1 0 0 0 0 1 0]
How can I do this in Octave? Thank you!
Or another way:
idx = [3; 5; 3; 4; 3; 2; 5; 1];
A = sparse (idx, [1:numel(idx)], 1)
A = Compressed Column Sparse (rows = 5, cols = 8, nnz = 8 [20%])
(3, 1) -> 1
(5, 2) -> 1
(3, 3) -> 1
(4, 4) -> 1
(3, 5) -> 1
(2, 6) -> 1
(5, 7) -> 1
(1, 8) -> 1
Which gives you a compressed column sparse (very efficient), you can convert this to a "normal, full matrix":
B = full (A)
B =
0 0 0 0 0 0 0 1
0 0 0 0 0 1 0 0
1 0 1 0 1 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 0 1 0
Try this:
idx = [3; 5; 3; 4; 3; 2; 5; 1];
n = numel(idx);
k = 5;
A=zeros(k,n);
A(sub2ind(size(A), idx, [1:n]')) = 1
Output is:
A =
0 0 0 0 0 0 0 1
0 0 0 0 0 1 0 0
1 0 1 0 1 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 0 1 0

Resources