Сумма независимой диагонали в матрице

Я сейчас готовлюсь к экзамену и пытаюсь разобраться с динамической матрицей. Я столкнулся с проблемой, касающейся вычисления суммы каждой диагонали матрицы, значения и размеры которой выбираются пользователем.
Цель моей программы — вывести, благодаря функции, параметрами которой являются матрица и ее размер, значение каждой диагональной суммы. Я покажу вам код и опишу его подробно.

----------------
| 52 | 35 | 5  |  Example of matrix.
----------------  Imagine the first diagonal to be the one which goes right-to-left
| 2  | 71 | 1  |  and only consists in the number "47".
----------------  The second diagonal would be the one which goes right-to-left and
| 3  | 60 | 25 |  consists in the number "15" and "79".
----------------  So to get the sum of the second diagonal it would be:
| 79 | 55 | 98 |
----------------  sum = m[n_rows - 1][diag - 2] + m[n_rows - 2][diag - 1]
| 47 | 15 | 66 |
----------------  When diag > columns, in order to avoid error regarding matrix size,
I should lower the quantity "n_rows - 1" by the quantity "diag - n_columns".

Это то, что я думал сделать, согласно моему описанию:

void diag_matrix(int** m, int righe, int colonne){//righe = rows, colonne = columns.
//M is the matrix.

// diag is the number of the diagonal I'm considering.
for(int diag = 1; diag < (righe + colonne); diag++){

int sum = 0;// the sum
int i = 0;// the counter of the cicle
int l = 0;// this is the value to riallign the row in case diag > column
int temp = diag;//I use this variable not to modify the value of diag.

// What I want is: when the column-index/row-index of the matrix reaches 0, the cicle will interrupt (after final iteration);
while(righe - i - l - 1 > 0 || diag - 1 - i > 0){

if (diag > colonne){//this condition changes l-value only if diag value is greater than column. Explanation outside the code
l = diag - colonne;//this is the value to subtract to row-index
temp = colonne;//this position is necessary to set column-index to its maxium.
}

sum = sum + m[righe - 1 - l - i][temp -1 - i];//pretty clear I think.
i++;//the i is incremented by one.

}// end of while-statement

cout << "Somma Diagonale " << diag << " = " << sum << ".\n";

}// end of for-statement

}//end of function declaration

Очевидно, что это не работает, но я не могу понять проблему.

8

Решение

Вы можете упростить свой код, находя начальную позицию каждой диагонали и затем шагая по матрице, пока координаты остаются внутри матрицы.
Что-то вроде этого:

#include <iostream>

using namespace std;

void diag_matrix(int** m, int rows, int cols)
{
for (int diag = 1; diag < rows + cols; diag++)
{
int x, y;
if (diag < rows)
{
y = rows - diag;
x = 0;
}
else
{
y = 0;
x = diag - rows;
}
int sum = 0;
cout << "Summing diagonal #" << diag << ":";
while ((x < cols) && (y < rows))
{
sum += m[y][x];
cout << " " << m[y][x];
x++;
y++;
}
cout << " result: " << sum << "." << endl;
}
}

int main(int argc, char* argv[])
{
int rows = 5, cols = 3;
int **m = new int*[rows];
for (int i = 0; i < rows; i++)
m[i] = new int[cols];
m[0][0] = 52; m[0][1] = 35; m[0][2] =  5;
m[1][0] =  2; m[1][1] = 71; m[1][2] =  1;
m[2][0] =  3; m[2][1] = 60; m[2][2] = 25;
m[3][0] = 79; m[3][1] = 55; m[3][2] = 98;
m[4][0] = 47; m[4][1] = 15; m[4][2] = 66;
diag_matrix(m, rows, cols);
for (int i = 0; i < rows; i++)
delete[] m[i];
delete[] m;
return 0;
}
2

Другие решения

(Раньше здесь был параграф, но при втором взгляде вы не ошиблись, о чем говорилось.)

Поскольку вы не публиковали в Code Reviews, вот решение вместо подробного анализа кода. (Если вы хотите, чтобы оригинальный подход работал, я бы предложил пошагово пройти его в отладчике и проверить, где ваши переменные вначале получают неправильное значение.) У него много шаблонов, чтобы он компилировался и выполнялся, но часть, которая вас больше всего интересует diag_sums() и его комментарии.

Одна идея здесь состоит в том, чтобы использовать ООП для автоматической проверки границ доступа к вашему массиву. Последнее очень важно для отлова отдельных ошибок и тому подобного. Вы можете отключить его в производственной среде, если хотите, но вы действительно не хотите отключать предупреждения, когда ваша программа переполнена буфером. Другие оптимизации здесь включают локальность доступа к данным и снижение прочности операций: вместо того, чтобы проверять на каждой итерации, достигли ли мы правого края и нижнего края, мы можем просто заранее вычислить длину каждой диагонали.

Поскольку определение диагонального числа К матрицы a с M Строки эквивалентны: все элементы a[i][j] такой что такой что MК знак равно яJ, алгоритм обеспечивает корректность, поддерживая инвариант, который сохраняется всякий раз, когда мы добавляем 1 к обоим я а также J, начиная, когда либо я или же J 0 и останавливается всякий раз, когда я знак равно M или же J знак равно N, то есть, проходя каждый шаг диагонали от левого или верхнего края к правому или нижнему краю, в зависимости от того, что наступит раньше.

#include <assert.h>
#include <iostream>
#include <stddef.h>
#include <stdlib.h>
#include <utility>
#include <vector>

using std::cin;
using std::cout;

template <typename T>
class matrix {
public:
matrix( const ptrdiff_t rows,
const ptrdiff_t cols,
std::vector<T>&& elems )
: rows_(rows), cols_(cols), elems_(elems)
{
assert( rows_ > 0 );
assert( cols_ > 0 );
assert( elems_.size() == static_cast<size_t>(rows_*cols_) );
}

matrix( const ptrdiff_t rows,
const ptrdiff_t cols,
const std::vector<T>& elems )
: matrix( rows, cols, std::move(std::vector<T>(elems)) )
{}

matrix( const matrix<T>& ) = default;
matrix( matrix<T>&& ) = default;
matrix& operator= ( const matrix<T>& ) = default;
matrix& operator= ( matrix<T>&& ) = default;

T& operator() ( const ptrdiff_t m, const ptrdiff_t n )
{
assert( m >= 0 && m < rows_ );
assert( n >= 0 && n < cols_ );
return elems_[static_cast<size_t>(m*cols_ + n)];
}

const T& operator() ( const ptrdiff_t m, const ptrdiff_t n ) const
{
/* Because this call does not modify any data, and the only reason the
* member function above cannot be const is that it returns a non-const
* reference to an element of elems, casting away the const qualifier
* internally and then returning a const reference is a safe way to
* re-use the code.
*/
matrix<T>& nonconst = *const_cast<matrix<T>*>(this);
return nonconst(m,n);
}

ptrdiff_t rows() const { return rows_; }
ptrdiff_t cols() const { return cols_; }

private:
ptrdiff_t rows_;
ptrdiff_t cols_;
std::vector<T> elems_;
};

template<typename T>
std::ostream& operator<< ( std::ostream& out, const matrix<T>& x )
/* Boilerplate to print a matrix. */
{
const ptrdiff_t m = x.rows(), n = x.cols();

for ( ptrdiff_t i = 0; i < m; ++i ) {
out << x(i,0);
for ( ptrdiff_t j = 1; j < n; ++j )
out << ' ' << x(i,j);

out << '\n';
} // end for

return out;
}

using elem_t = int;

std::vector<elem_t> diag_sums( const matrix<elem_t>& a )
/* Return a vector of all the diagonal sums of a.
*
* The first diagonal sum is a(rows-1,0)
* The second is a(rows-2,0) + a(rows-1,1)
* The third is a(rows-3,0) + a(rows-2,1) + a(rows-1,2)
* And so on.  I.e., the kth diagonal is the sum of all elements a(i,j) such
* that i - j == rows - k.
*
* If a is a M×N matrix, there are M diagonals starting in column zero, and
* N-1 diagonals (excluding the one containing a(0,0) so we don't count it
* twice) starting in row 0.  We process them bottom to top, then left to
* right.
*
* The number of elements in a diagonal starting at a(i,0) is min{M-i, N}.  The
* number of elements in a diagonal starting at a(0,j) is min{M, N-j}.  This is
* because a diagonal stops at either the bottom edge or the left edge of a.
*/
{
const ptrdiff_t m = a.rows(), n = a.cols();
std::vector<elem_t> result;
result.reserve( static_cast<size_t>(m + n - 1) );

for ( ptrdiff_t i = m-1; i > 0; --i ) {
elem_t sum = 0;

const ptrdiff_t nk = (m-i) < n ? (m-i) : n;
for ( ptrdiff_t k = 0; k < nk; ++k )
sum += a(i+k, k);

result.emplace_back(sum);
} // end for i

for ( ptrdiff_t j = 0; j < n; ++j ) {
elem_t sum = 0;

const ptrdiff_t nk = m < (n-j) ? m : (n-j);
for ( ptrdiff_t k = 0; k < nk; ++k )
sum += a(k, j+k);

result.emplace_back(sum);
} // end for j

return result;
}

matrix<elem_t> read_input_matrix( const int row, const int column )
/* Reads in row*column consecutive elements from cin and packs them into a
* matrix<elem_t>.
*/
{
assert(row > 0);
assert(column > 0);

const ptrdiff_t nelements = row*column;
assert(nelements > 0); // Check for overflow.

std::vector<elem_t> result;
result.reserve(static_cast<size_t>(nelements));

for ( ptrdiff_t i = nelements; i > 0; --i ) {
int x;
cin >> x;
assert(cin.good());
result.push_back(x);
}

return matrix<elem_t>( row,
column,
std::move(result) );
}

template<typename T>
bool print_sequence( const T& container )
/* Prints the contents of a container in the format
* "{47, 94, 124, 160, 148, 36, 5}".
*/
{
cout << "{";

if ( container.begin() != container.end() )
cout << *container.begin();

for ( auto it = container.begin() + 1; it < container.end(); ++it )
cout << ", " << *it;

cout << "}\n";

return cout.good();
}

/* A simple test driver that reads in the number of rows, the number of
* columns, and then row*columns int values, from standard input.  It
* then passes the result to diag_matrix(), E.g.:
*
* 5 3
* 52 35  5
*  2 71  1
*  3 60 25
* 79 55 98
* 47 15 66
*/
int main()
{
int rows, columns;
cin >> rows;
cin >> columns;

assert(cin.good());

const matrix<elem_t> input_matrix = read_input_matrix( rows, columns );
// cout << input_matrix; // Instrumentation.
const std::vector<elem_t> sums = diag_sums(input_matrix);

print_sequence(sums);

return EXIT_SUCCESS;
}

Вы также можете просто сделать print_sequence(diag_sums(read_input_matrix( rows, columns ))),

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector