Finding all adjacent elements in a 2D array

后端 未结 5 1405
半阙折子戏
半阙折子戏 2021-02-15 18:07

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          


        
相关标签:
5条回答
  • 2021-02-15 18:51

    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.

    0 讨论(0)
  • 2021-02-15 18:57
    1. define another 2d array of the same size, initialize all cells to 0
    2. set maxval to 0
    3. if helper array is full of 1's go to 5, otherwise find a cell with 0 and do:
      3.1 change value of the cell to 1
      3.2 set a counter to 1
      3.3 check all adjacent cells, if they're 0 in the helper array and the same value as current cell in the input array then counter++ and go to 2.1 with new coordinates.
    4. maxval = max(maxval,counter), go to 3
    5. return maxval

    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.

    0 讨论(0)
  • 2021-02-15 19:00

    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

    0 讨论(0)
  • 2021-02-15 19:08

    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

    0 讨论(0)
  • 2021-02-15 19:09

    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);
    }
    
    0 讨论(0)
提交回复
热议问题