I am working on a project where at one point I am stuck.
My question is for example I have the following 2D array containing 3 different integers.
2 2 2
You could treat this like a picture in a paint application. Perform a flood-fill on each element in your 2D array (unless its filled already by something else) and keep track how many pixels you filled in each step.
If your array is declared like
int elements[5][5];
Then introduce a second array which tells whether you filled an element already (if you like, use a different type like bool
if thats's okay in your C program):
int pixelFilled[5][5];
memset( pixelFilled, 0, sizeof( pixelFilled ) );
Next, write a recursive function which performs a flood fill and returns the numbers of elements which were filled (I'm writing this from the top of my head, no guarantee whatsoever that this function works as it is):
int floodFill( int x, int y ) {
int filledPixels = 0;
if ( !pixelFilled[x][y] ) {
++filledPixels;
pixelFilled[x][y] = 1;
} else {
return 0;
}
if ( x < 4 && elements[x+1][y] == elements[x][y] )
filledPixels += floodFill( x + 1, y );
if ( x > 0 && elements[x-1][y] == elements[x][y] )
filledPixels += floodFill( x - 1, y );
if ( y < 4 && elements[x][y+1] == elements[x][y] )
filledPixels += floodFill( x, y + 1 );
if ( y > 0 && elements[x][y-1] == elements[x][y] )
filledPixels += floodFill( x, y - 1 );
return filledPixels;
}
Finally, iterate over your array and try to fill it completely. Keep track of the largest filled array:
int thisArea = 0;
int largestArea = 0;
int x, y;
for ( y = 0; y < 5; ++y ) {
for ( x = 0; x < 5; ++x ) {
thisArea = floodFill( x, y );
if (thisArea > largestArea ) {
largestArea = thisArea;
}
}
}
Now, largestArea
should contain the size of the longest chain of adjacent elements.
steps 3.1-3.3 should be implemented as a recursive function which takes coordinate and both arrays as arguments and returns 1+the sum of the returned values from the recursive calls.
I love this kind of problems :-) so here it is my answer.
As said by Frerich Raabe, this can be solved with a floodFill function. For example, opencv
library would provide such a function off the shelf.
Please forgive me if in the following code you'll find traces of C++, in case they should be simple to be replaced.
typedef struct Point {
int x;
int y;
} Point;
int areaOfBiggestContiguousRegion(int* mat,int nRows, int nCols) {
int maxArea = 0;
int currValue, queueSize, queueIndex;
int* aux;
Point queue[1000]; //Stores the points I need to label
Point newPoint, currentPoint;
int x,y,x2,y2;
//Code: allocate support array aux of same size of mat
//Code: fill aux of zeros
for (y = 0; y < nRows; y++)
for (x = 0; x < nCols; x++)
if (aux[y * nCols + x] == 0) {//I find a pixel not yet labeled, my seed for the next flood fill
queueIndex = 0; //Contains the index to the next element in the queue
queueSize = 0;
currValue = mat[y * nCols + x]; //The "color" of the current spot
aux[y * nCols + x] = 1;
newPoint.x = x;
newPoint.y = y;
queue[queueSize] = newPoint;
queueSize++;
while(queueIndex != queueSize) {
currPoint = queue[queueIndex];
queueIndex++;
//Look left, right, up, down
x2 = currPoint.x - 1;
y2 = currPoint.y;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (x2 >= 0 && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
x2 = currPoint.x + 1;
y2 = currPoint.y;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (x2 < nCols && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
x2 = currPoint.x;
y2 = currPoint.y - 1;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (y2 >= 0 && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
x2 = currPoint.x;
y2 = currPoint.y + 1;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (y2 < nRows && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
} //while
if (queueSize > maxArea)
maxArea = queueSize; //If necessary we could store other details like currentValue
}//if (aux...
return maxArea;
}
Note: In C++ using std containers and a constructor for Point
it becomes much more compact
Suppose your matrix is a graph, and the elements are vertices. Two vertices are connected if they are adjacent and have the same value. If you perform any search in that graph, be it Breadth-First Search or Depth-First Search, you'll get exactly what you want. HTH
Easier to draw than to explain...
2 2 2 2 1 => A A A A B => (A: 4, B: 1)
1 2 2 2 1 => C A A A B => (A: 3 + 4, B: 1 + 1, C: 1)
3 3 2 3 2 => D D A E F => (A: 1 + 7, B: 2, C: 1, D: 2, E: 1, F: 1)
3 1 3 3 1 => D G E E G => (A: 8, B: 2, C: 1, D: 2 + 1, E: 2 + 1, F: 1, G: 1)
1 1 2 3 1 => ...
1 3 1 3 3 => ...
update:
And now, with some real code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define ROWS 6
#define COLS 5
unsigned char eles[ROWS][COLS] = { { 2, 2, 2, 2, 1 },
{ 1, 2, 2, 2, 1 },
{ 3, 3, 2, 3, 2 },
{ 3, 1, 3, 3, 1 },
{ 1, 1, 2, 3, 1 },
{ 1, 3, 1, 3, 3 } };
struct zone {
int acu;
int row, col;
int refs;
};
typedef struct zone zone;
zone *
new_zone(int row, int col) {
zone *z = (zone *)malloc(sizeof(zone));
z->col = col;
z->row = row;
z->refs = 1;
z->acu = 0;
}
void croak (const char *str) {
fprintf(stderr, "error: %s\n", str);
exit(1);
}
void
free_zone(zone *z) {
if (z->refs != 0) croak("free_zone: reference count is not cero");
free(z);
}
zone *
ref_zone(zone *z) {
z->refs++;
return z;
}
void
unref_zone(zone *z) {
z->refs--;
if (!z->refs) free_zone(z);
}
int
main() {
zone *last[COLS];
zone *current[COLS];
zone *best = new_zone(0, 0);
int i, j;
memset(last, 0, sizeof(last));
for (j = 0; j < ROWS; j++) {
for (i = 0; i < COLS; i++) {
unsigned int ele = eles[j][i];
zone *z;
/* printf("analyzing ele: %d at row %d, col: %d\n", ele, j, i); */
if (i && (ele == eles[j][i-1])) {
/* printf(" equal to left element\n"); */
z = ref_zone(current[i-1]);
if (j && (ele == eles[j-1][i])) {
zone *z1 = last[i];
/* printf(" equal to upper element\n"); */
if (z != z1) {
int k;
/* printf(" collapsing zone %p\n", z1); */
z->acu += z1->acu;
for (k = 0; k < COLS; k++) {
if (last[k] == z1) {
last[k] = ref_zone(z);
unref_zone(z1);
}
}
for (k = 0; k < i; k++) {
if (current[k] == z1) {
current[k] = ref_zone(z);
unref_zone(z1);
}
}
}
}
}
else if (j && (ele == eles[j-1][i])) {
/* printf(" equal to upper element\n"); */
z = ref_zone(last[i]);
}
else {
/* printf(" new element\n"); */
z = new_zone(j, i);
}
z->acu++;
current[i] = z;
/* printf(" element zone: %p\n", z); */
}
for (i = 0; i < COLS; i++) {
if (j) unref_zone(last[i]);
last[i] = current[i];
if (best->acu < current[i]->acu) {
unref_zone(best);
best = ref_zone(current[i]);
/* printf("best zone changed to %p at row; %d, col: %d, acu: %d\n", best, best->row, best->col, best->acu); */
}
}
}
printf("best zone is at row: %d, col: %d, ele: %d, size: %d\n", best->row, best->col, eles[best->row][best->col], best->acu);
}