简体   繁体   中英

2D array: Sum of elements of a subsquare of the 2d array

Given a 2D array, I have no trouble adding all of its elements into a sum variable. Say a 4x4 array:

1 2 3 4

1 2 2 3

1 2 2 2

1 1 3 3

My code to sum all its elements is to do a for loop:

for (i = 0; i < rows; i++)
{
 for (j = 0; j < columns; j++)
 {
   sum += somearray[i][j];
 }
}  

I believe this is right assuming all variables are properly declared.However, I am having trouble wrapping my head in doing a sum of a 3x3 cell in the same array. I am suppose to find the 3x3 cell that yields the lowest sum.

for (i = 0; i < 3; i++)
{
 for (j = 0; j < 3; j+++
 {
   sum += somearray[i][j];
 }
}

I believe this sums a 3x3 cell starting from somearray[0][0]. I am at a lost at how to go from here to get all other 3x3 cell combinations and compare them to find the lowest 3x3 cell value. If I could the next 3x3 cell, I know I could just use a comparison statement of some sort and change the sum variable to the next sum if its lower.

How can I accomplish this? Do I need to add more layers to my for loops?

Let's start with definitions:

size_t rows; // number of rows
size_t columns; // number of columns
int array[rows][columns];

Helper function:

int sum(size_t row, size_t column)
{
   int res = 0;

   if (row > rows - 3 || column > columns - 3)
   {
      abort(); // we can out of index operations here...
   }

   for (size_t i = 0; i < 3; ++i)
   {
       for (size_t j = 0; j < 3; ++j)
       {
           res += array[i + row][j + column];
       }
   }
   return res;
}

Now we can start...

int min_value = INT_MAX;  // Just the maximum we can imaging
size_t min_row = 0, min_column = 0; // whatever

for (size_t i = 0; i <= rows - 3; ++i)
{
   for (size_t j = 0; j <= columns - 3; ++j)
   {
      int value = sum(i, j);
      if (value < min_value)
      {
         min_value = value;
         min_row = i;
         min_column = j;
      }
   }
}
... // done - here min_value is the minimum sum,
    // and min_row, min_column are indexes of the 3x3 entry

The code you have written, with both for loops stopping at 3, makes it possible to calculate the number that you want in a 3x3 submatrix that starts from [0][0], as you said. What you need to do now is:

  1. Identifying all the starting points you have, making sure that there are 3 rows and 3 columns from there, including the element you are at, and calling the function once per each possible starting point, and

  2. Extending that code so that it can start from any point in the matrix.

Here is how we can proceed for point 1:

You have a 4x4 matrix, but we can easily generalize it to a NxM one. N means that there are N rows, that is, each column has N elements. So let's consider a column. If you have N elements, how many groups of 3 consecutive elements can you find? Watch out, it isn't N-3 (which looks like an obvious answer, but it's wrong):

  • with N=3 elements it's only 1 (if you have 123, the group is 123)
  • with N=4 elements there are 2 (if you have 1234, the groups are 123 and 234)
  • with N=5 elements there are 3 (if you have 12345, the groups are 123, 234, 345)

So in general you have N - 3 + 1 groups (of course you can think it's N-2, but I prefer to express the 3 because that is the number of elements that we are taking each time).

The same approach can be applied to columns: if they are M you can take M - 3 + 1 groups.

That said, how many 3x3 submatrices can you find in a NxM matrix? First you can find all the "vertical" groups of 3, which are N-3+1. For each of them, how many "horizontal" groups of 3 can you form? M-3+1. Then you have a total of (N-3+1)*(M-3+1) 3x3 submatrices. This is the number of iterations you have to make to check each submatrix. Each of these N-3+1 elements is a row (we are moving vertically, that is, along a column, so these are rows), so this is an element at which we can start checking for a matrix - provided we have enough horizontal space, that is, there are enough columns. And for each of these rows we have to check M-3+1 columns (moving horizontally along a row), where a 3x3 submatrix can start.

int min_found = 0; // So far we haven't found a minimum yet
int min_value, min_row, min_column;
int max_rows    = (N-3+1);
int max_columns = (M-3+1);

for (int start_row = 0; start_row < max_rows; start_row++) {
    for (int start_column = 0; start_column < max_columns; start_column++) {
        int current_sum = calculate_sum_of_submatrix(start_row, start_column);
        if ( (min_found == 0) || (min_found == 1 && current_sum < min_value) ) 
            min_value = current_sum;
            min_row    = start_row;
            min_column = start_column;
            min_found = 1;
        }
    }
}

cout << "The 3x3 submatrix whose elements have the minimum sum "
     << "starts at row " << min_row << " and column " << min_column
     << ", and the sum is " << min_sum << endl;

In your case (N=4, M=4) we would have N-3+1=2 rows to check and M-3+1=2 columns. So we would start at [0][0], then the inner loop would bring us to [0][1], then the inner loop would finish, and we would continue to the outer one, which would take us to row 1, and the inner loop would check [1][0] and [1][1]. Then it would be over. By this time we would have checked all 4 3x3 submatrices and we would know the minimum.

Now, point 2: we have to adapt the function that you already have, so that instead of always starting from [0][0] it starts from where we want. It's easy, we just have to read the matrix at a place that is given by the sum of the starting position (which in your code was always [0][0]) and the [i][j] indices that you already have. Like this:

int calculate_sum_of_submatrix(int start_row, int start_column) {
    int sum = 0;
    for (int i = 0; i < 3; i++) {     // I would replace i with "submatrix_row"
        for (int j = 0; j < 3; j++) { // I would replace j with "submatrix_column"
            sum += somearray[start_row + i][start_column + j];
        }
    }
    return sum;
}

That should do it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM