Home > Software engineering >  Do not know how to change "under the diagonal" numbers to negative in a matrix
Do not know how to change "under the diagonal" numbers to negative in a matrix

Time:10-21

My task is to let user enter number n and then the matrix forms with dimensions n*n. Program then, makes diagonal have zeros, number above diagonal have to be positive numbers (1,2,...,n), and numbers below diagonal have to be negative numbers (-1,-2,...,-n). I successfully made the matrix after 8 hours of thinking, but the numbers below diagonal which must be negative, are positive. I cannot find where the problem is.

Input sample:

Enter n: 5
Matrix:
 0   1   2   3   4
-1   0   1   2   3
-2  -1   0   1   2
-3  -2  -1   0   1
-4  -3  -2  -1   0

My output:

Enter n: 5
Matrix:
 0   1   2   3   4
 1   0   1   2   3
 2   1   0   1   2
 3   2   1   0   1
 4   3   2   1   0

My code:

#include <bits/stdc  .h>
using namespace std;
void solve(long long n)
{
    long long array1[n - 1][n - 1], array2[n][n];
 
    for (long long i = 0; i < n - 1;   i)
        array1[0][i] = i   1;
 
    for (long long i = 1; i < n - 1;   i)
        for (long long j = 0; j < n - 1;   j)
            array1[i][j]
                = array1[i - 1][(j   1) % (n - 1)];
 
    for (long long i = 0; i < n - 1;   i)
        for (long long j = 0; j < n - 1;   j)
            array2[i][j] = array1[i][j];
    for (long long i = 0; i < n;   i)
        array2[i][n - 1] = array2[n - 1][i] = 0;
        for (long long i = 0; i < n;   i) {
        long long t0 = array2[i][i];
        long long t1 = array2[i][n - 1];
 
        swap(array2[i][i], array2[i][n - 1]);
 
        array2[n - 1][i] = t0;
    }
    for (long long i = 0; i < n;   i) {
        for (long long j = 0; j < n;   j)
            cout << array2[i][j] << " ";
        cout << endl;
    }
}
 
int main()
{
    long long n = 5;
    solve(n);
 
    return 0;
}

CodePudding user response:

Per my comment, the key is to find a pattern that you can exploit. We're also going to stray away from C-arrays, not just because of the SO meme about recommending vectors even when it's not pertinent, but because they're actually the better data structure for this use-case.

You end up using VLAs, or Variable-Length Arrays. They are not a part of C , but are an optional part of C. Support for VLAs can disappear at any time, and on top of that, they're not safe for the stack as was mentioned in a different comment.

Before we get into a solution, I should address your first two lines of code. Each line has been linked to an answer telling you why they're bad:

#include <bits/stdc .h>
using namespace std;

So, what's this magical pattern? I chose to look at a row individually. In a typical nested for loop iteration through a square 2D array, the diagonal occurs when the row number is equal to the column number. Diagonals fall on matrix[i][i] if i is the variable used to iterate the rows.

The pattern comes in examining the values of of a row. Values to the left should be negative and values to the right should be positive. Not just that, but the values should be the distance from the diagonal element.

Well, if I use j as my column counter, the value is as simple as j - i. Consider the second row, i = 1.

-1 0 1 2 3

This is row 1, so [1][1] is the zero element. At [1][0], j - i == -1, and so on. Finding the pattern greatly simplifies the code you need to write. Here's an implementation:

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <vector>

void solve(const long long n) {
  // Declare and zero-initialize
  std::vector<std::vector<int>> v(n, std::vector<int>(n, 0));

  // Fill array
  for (std::size_t i = 0; i < v.size();   i) {
    for (std::size_t j = 0; j < v[i].size();   j) {
      v[i][j] = static_cast<int>(j) - static_cast<int>(i);
    }
  }

  // Find length of biggest number, v[0][n - 1]; for printing purposes
  int largest = v[0][n - 1];
  int numLength = 0;
  while (largest != 0) {
      numLength;
    largest /= 10;
  }

  // Print array
  for (auto i : v) {
    for (auto j : i) {
      std::cout << std::setw(numLength   2) << j << ' ';
    }
    std::cout << '\n';
  }
}

int main(int argc, char* argv[]) {
  if (argc != 2) return 1;

  long long n = std::atoi(argv[1]);
  solve(n);
}

Sample outputs:

❯ ./a.out 5
  0   1   2   3   4 
 -1   0   1   2   3 
 -2  -1   0   1   2 
 -3  -2  -1   0   1 
 -4  -3  -2  -1   0 

❯ ./a.out 15
   0    1    2    3    4    5    6    7    8    9   10   11   12   13   14 
  -1    0    1    2    3    4    5    6    7    8    9   10   11   12   13 
  -2   -1    0    1    2    3    4    5    6    7    8    9   10   11   12 
  -3   -2   -1    0    1    2    3    4    5    6    7    8    9   10   11 
  -4   -3   -2   -1    0    1    2    3    4    5    6    7    8    9   10 
  -5   -4   -3   -2   -1    0    1    2    3    4    5    6    7    8    9 
  -6   -5   -4   -3   -2   -1    0    1    2    3    4    5    6    7    8 
  -7   -6   -5   -4   -3   -2   -1    0    1    2    3    4    5    6    7 
  -8   -7   -6   -5   -4   -3   -2   -1    0    1    2    3    4    5    6 
  -9   -8   -7   -6   -5   -4   -3   -2   -1    0    1    2    3    4    5 
 -10   -9   -8   -7   -6   -5   -4   -3   -2   -1    0    1    2    3    4 
 -11  -10   -9   -8   -7   -6   -5   -4   -3   -2   -1    0    1    2    3 
 -12  -11  -10   -9   -8   -7   -6   -5   -4   -3   -2   -1    0    1    2 
 -13  -12  -11  -10   -9   -8   -7   -6   -5   -4   -3   -2   -1    0    1 
 -14  -13  -12  -11  -10   -9   -8   -7   -6   -5   -4   -3   -2   -1    0 

It is hopefully very apparent how much simpler the solve() function becomes when we are able to take advantage of a pattern as opposed to brute-forcing it.

CodePudding user response:

Just put a condition in nested for loop to check for the elements having index_of_row greater than index_of_column and make them negative.

CodePudding user response:

Say you have a matrix with rows indexed by i and columns indexed by j.

The middle diagonal of the matrix is simply matrix[i][i]. So, anything below the middle line we can simply turn negative. I added the following for loop after your code and got it to work (formatting is slightly off, but you can fix that):

for (long long i = 0; i < n;   i) {
    for (long long j = 0; j < n;   j) {
        if ( j < i ) {
            array2[i][j] *= -1; // make it negative
        }
    }
}

The complete file (just copying and pasting your code here), with my modification is the following:

#include <bits/stdc  .h>
using namespace std;
void solve(long long n)
{
    long long array1[n - 1][n - 1], array2[n][n];
 
    for (long long i = 0; i < n - 1;   i)
        array1[0][i] = i   1;
 
    for (long long i = 1; i < n - 1;   i)
        for (long long j = 0; j < n - 1;   j)
            array1[i][j]
                = array1[i - 1][(j   1) % (n - 1)];
 
    for (long long i = 0; i < n - 1;   i)
        for (long long j = 0; j < n - 1;   j)
            array2[i][j] = array1[i][j];
    for (long long i = 0; i < n;   i)
        array2[i][n - 1] = array2[n - 1][i] = 0;
        for (long long i = 0; i < n;   i) {
        long long t0 = array2[i][i];
        long long t1 = array2[i][n - 1];
 
        swap(array2[i][i], array2[i][n - 1]);
 
        array2[n - 1][i] = t0;
    }

    for (long long i = 0; i < n;   i) {
        for (long long j = 0; j < n;   j) {
            if ( j < i ) {
                array2[i][j] *= -1; // make it negative
            }
        }
    }

    for (long long i = 0; i < n;   i) {
        for (long long j = 0; j < n;   j)
            cout << array2[i][j] << " ";
        cout << endl;
    }
}
 
int main()
{
    long long n = 5;
    solve(n);
 
    return 0;
}

Note: You'd also have much cleaner code by putting #define ll long long at the top of your file, then replacing all instances of long long with ll. Makes the code much less clunky. You could always just use a standard int as well, especially for loop indices (i and j) - I doubt you are looping more than 2,147,483,647 times, haha.

  • Related