Поиск всех соседних элементов в двумерном массиве в C - PullRequest
7 голосов
/ 09 декабря 2010

Я работаю над проектом, в котором однажды я застрял.

Мой вопрос, например, у меня есть следующий 2D-массив, содержащий 3 разных целых числа.

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 

Что мне нужно, так это найти самую длинную цепочку соседних элементов массива из любого числа, содержащегося в массиве.

Как и в приведенном выше массиве, самая длинная цепочка имеет цифру 2.

2 2 2 2
  2 2 2
    2

Может ли кто-нибудь просто подсказать мне, что я должен сделать для достижения этой цели?

Спасибо.

Ответы [ 5 ]

0 голосов
/ 12 декабря 2013

Мне нравятся такие проблемы :-) так что вот мой ответ. По словам Фрериха Раабе, это можно решить с помощью функции floodFill. Например, библиотека opencv может предоставить такую ​​функцию с полки.

Пожалуйста, прости меня, если в следующем коде вы найдете следы C ++, на случай, если их будет просто заменить.

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;
}

Примечание: в C ++ с использованием контейнеров std и конструктора для Point он становится намного более компактным

0 голосов
/ 09 декабря 2010

Вы можете рассматривать это как рисунок в приложении для рисования.Выполните flood-fill для каждого элемента в вашем 2D-массиве (если он уже не заполнен чем-то другим) и отслеживайте, сколько пикселей вы заполнили на каждом шаге.

Если ваш массив объявленкак

int elements[5][5];

Затем введите второй массив, который сообщает, заполнил ли вы уже элемент (если хотите, используйте другой тип, например bool, если это нормально в вашей C-программе):

int pixelFilled[5][5];
memset( pixelFilled, 0, sizeof( pixelFilled ) );

Далее, напишите рекурсивную функцию, которая выполняет заливку и возвращает количество заполненных элементов (я пишу это из головы, я не гарантирую, что эта функция работает так, как она есть):

int floodFill( int x, int y ) {
  int filledPixels = 0;
  if ( !pixelFilled[x][y] ) {
    ++filledPixels;
    pixelFilled[x][y] = 1;
  }
  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;
}

Наконец, переберите свой массив и попробуйте заполнить его полностью.Отслеживайте самый большой заполненный массив:

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;
    }
  }
}

Теперь largestArea должен содержать размер самой длинной цепочки смежных элементов.

0 голосов
/ 09 декабря 2010

Проще нарисовать, чем объяснить ...

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 => ...

обновление

А теперь с реальным кодом:

#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 голосов
/ 09 декабря 2010
  1. определить другой двумерный массив того же размера, инициализировать все ячейки 0
  2. установить maxval в 0
  3. если вспомогательный массив полон 1, переходите к 5, в противном случае найдите ячейку с 0 и выполните:
    3.1 изменить значение ячейки на 1
    3.2 установить счетчик на 1
    3.3 проверьте все смежные ячейки, если они равны 0 в массиве помощников и имеют то же значение, что и текущая ячейка во входном массиве, затем counter ++ и перейдите к 2.1 с новыми координатами.
  4. maxval = max (maxval, counter), перейти к 3
  5. возврат maxval

шаги 3.1-3.3 должны быть реализованы как рекурсивная функция, которая принимает координаты и оба массива в качестве аргументов и возвращает 1 + сумму возвращенных значений из рекурсивных вызовов.

0 голосов
/ 09 декабря 2010

Предположим, ваша матрица - это граф, а элементы - вершины. Две вершины связаны, если они смежные и имеют одинаковое значение. Если вы выполните поиск в этом графике, будь то Поиск в ширину или Поиск в глубину , вы получите именно то, что вам нужно. НТН

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...