I have been struggling to solve the following question using Recessive Backtracking in C++. The problem is that it does not backtrack. I tracked my algorithm manually on a paper and it works on the paper. So problem is I don't know how to implement that in C++. Any help will be appreciated.
Question:
Given a 2-dimensional grid representing elevations of a map, determine the lowest and highest points and whether there is a path between them that never goes down.
Input
Your program will receive the following command line arguments:
<fname> File name for the 2-dimensional map
<M> Number of rows
<N> Number of columns
Output
Your program should write 5 values to the standard output: Lr Lc Hr Hc YESNO where Lr Lc are the row and column of the lowest point in the grid, Hr Hc are the row and column of the highest point in the grid, and YESNO is the word: yes if there is a path from the lowest point to the highest point that never goes down and no if there is no such path. Specifically, the path starts at the lowest point and can only go from a point to one of its 4-neighbors (left, right, up, or down) that does NOT have a lower elevation than the point. Input will be such that there is a unique solution.
The problem is with the "path" function.
#include <iostream>
#include <fstream>
#include<string>
#include <vector>
#include <algorithm>
#include <iostream>
#include<sstream>
// using namespace std;
void ReadFile(std::string fname, std::vector<std::vector<int>> *const vec_2d);
// What about min? row and col are initially the min, but then get updated
void min_max(std::vector<std::vector<int>> *const vec_2d,
std::vector<int> &vec_1d,
int num_rows,
int num_cols,
int &row,
int &col,
int &idx_i_max,
int &idx_j_max,
int &cur_val); //grid is vec_2d??????
int path(std::vector<int> vec_1d,
int row,
int col,
int num_rows,
int num_cols,
int idx_i_max,
int idx_j_max,
int &cur_val); // bool *visited is a pointer type bool which could be a 2-d array??
int main(int argc, char *argv[])
{
std::vector<std::vector<int>> vec_2d;
std::vector<int> vec_1d;
// declare variables
int num_rows, num_cols, row, col, idx_i_max, idx_j_max, cur_val;
std::string fname;
// get .txt file containing the grid
fname = argv[1]; //string of file name
num_rows = atoi(argv[2]); // convert argument strings to integers
num_cols = atoi(argv[3]);
// bool visited[100][100];
//2D vector initialized with user defined size
// std::vector<std::vector<int>> visited(num_rows, std::vector<int>(num_cols));
ReadFile(fname, &vec_2d); //reading the .txt file and assigning to vec_2d
min_max(&vec_2d,
vec_1d,
num_rows,
num_cols,
row,
col,
idx_i_max,
idx_j_max,
cur_val);
path(vec_1d, row, col, num_rows, num_cols, idx_i_max, idx_j_max, cur_val);
}
void ReadFile(std::string fname, std::vector<std::vector<int>> *const vec_2d)
{ //it is a pointer to a vector,therefore, after end of func, it will still exist // Create the input filestream - opens the file & prepares it for reading
std::ifstream file(fname);
std::string str; // Temporary string to hold a single line of the file
while (std::getline(file, str))
{ // Reads all lines in the file, 1 at at time
std::vector<int> new_row; // Creates a temporary vector to represent one row
std::istringstream ss(str); // Converts our string into a stringstream
int token; // Temp int to store a converted value from a line
while (ss >> token)
{ // Reads all values from the stringstream (current row), converts to int
new_row.push_back(token); // Adds the converted value to the row
}
vec_2d->push_back(new_row); // Pushes our constructed vector of ints to the 2D vector
}
}
void min_max(std::vector<std::vector<int>> *const vec_2d,
std::vector<int> &vec_1d,
int num_rows,
int num_cols,
int &row,
int &col,
int &idx_i_max,
int &idx_j_max,
int &cur_val)
{ //I dont need any argument for this func
//Converting 2-d vec to 1-d to find loc of min and max
for (int i = 0; i < (*vec_2d).size(); i++)
{
for (int j = 0; j < (*vec_2d)[i].size(); j++)
{
vec_1d.push_back((*vec_2d)[i][j]);
}
}
// finding the max and min values in the grid vector and save thier index (max_idx and min_idx)
int max_idx, min_idx; // Initialize two int for index of max and min values
//
int maxElementIndex = std::max_element(vec_1d.begin(), vec_1d.end())
- vec_1d.begin(); //max elem index //I need to convert 2d to 1d vector to use this func
int minElementIndex = std::min_element(vec_1d.begin(), vec_1d.end())
- vec_1d.begin(); //min elem index
//convert 1-d vec idx to 2-d vec idx
idx_i_max = (maxElementIndex / num_cols) + 1; //actual idx + 1
idx_j_max = (maxElementIndex % num_cols) + 1; //actual idx + 1
int idx_i_min = (minElementIndex / num_cols) + 1; //actual idx + 1
int idx_j_min = (minElementIndex % num_cols) + 1; //actual idx + 1
// The initial current value is the minimum
cur_val = *std::min_element(vec_1d.begin(), vec_1d.end());
//loc of min will be our start point as below
row = idx_i_min; //actual idx + 1
col = idx_j_min; //actual idx + 1
// print i and j idx of min and max respectively (with a space after each)
std::cout << idx_i_min << " ";
std::cout << idx_j_min << " ";
std::cout << idx_i_max << " ";
std::cout << idx_j_max << " "; //This prints are working fine
// A recursive backtracking function to go over all cells. base case is when all directions are impossible, then retuen 0
}
//row and col will be changed in every recursion. should they be const???
int path(std::vector<int> vec_1d,
int row,
int col,
int num_rows,
int num_cols,
int idx_i_max,
int idx_j_max,
int &cur_val)
{
// std::cout<<"test"<<std::endl;
std::cout << std::endl << row << " " << col << std::endl; // it atops at the second cell
// std::cout<<cur_val<<std::endl;//it prints the start point twice
// if the evaluating neighbor cell is equal to max value
if (row == idx_i_max && col == idx_j_max)
{ //base case
std::cout << "yes";
return 1;
}
else
{
cur_val = vec_1d[((row - 1) * num_cols) + (col - 1)]; //updating the current value
//Checking the north neighbor (COND1)
if (row - 1 > 0
&& vec_1d[((row - 1 - 1) * num_cols) + (col - 1)] >= cur_val)
{ //if the north cell is -1
vec_1d[((row - 1) * num_cols) + (col - 1)] = -1; // making the current cell as visited
path(vec_1d,
row - 1,
col,
num_rows,
num_cols,
idx_i_max,
idx_j_max,
cur_val);
return 1;
}
//Checking the south neighbor(COND2)
if (row + 1 <= num_rows
&& vec_1d[((row + 1 - 1) * num_cols) + (col - 1)] >= cur_val)
{
vec_1d[((row - 1) * num_cols) + (col - 1)] = -1;
path(vec_1d,
row + 1,
col,
num_rows,
num_cols,
idx_i_max,
idx_j_max,
cur_val);
return 1;
}
//Checking the west neighbor(COND3)
if (col - 1 > 0
&& vec_1d[((row - 1) * num_cols) + (col - 1 - 1)] >= cur_val)
{
vec_1d[((row - 1) * num_cols) + (col - 1)] = -1;
path(vec_1d,
row,
col - 1,
num_rows,
num_cols,
idx_i_max,
idx_j_max,
cur_val);
return 1;
}
//Checking the east neighbor(COND4)
if (col + 1 <= num_cols
&& vec_1d[((row - 1) * num_cols) + (col + 1 - 1)] >= cur_val)
{
vec_1d[((row - 1) * num_cols) + (col - 1)] = -1;
path(vec_1d,
row,
col + 1,
num_rows,
num_cols,
idx_i_max,
idx_j_max,
cur_val);
return 1;
}
// return 0;
}
// FORGET ABOUT PRINTING YES/NO. FOCUS ON THE PRINT OF CURRENT CELL
// if(path){
// std::cout<<"yes";
// }
// else{
// std::cout<<"no";
// }
}
Here's a hint:
^ g++ Foo.cpp -Wall --std=c++17 -o Foo
Foo.cpp: In function ‘void min_max(std::vector<std::vector<int> >*, std::vector<int>&, int, int, int&, int&, int&, int&, int&)’:
Foo.cpp:107:23: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
for (int i = 0; i < (*vec_2d).size(); i++)
~~^~~~~~~~~~~~~~~~~~
Foo.cpp:110:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
for (int j = 0; j < (*vec_2d)[i].size(); j++)
~~^~~~~~~~~~~~~~~~~~~~~
Foo.cpp:117:9: warning: unused variable ‘max_idx’ [-Wunused-variable]
int max_idx, min_idx; // Initialize two int for index of max and min values
^~~~~~~
Foo.cpp:117:18: warning: unused variable ‘min_idx’ [-Wunused-variable]
int max_idx, min_idx; // Initialize two int for index of max and min values
^~~~~~~
Foo.cpp: In function ‘int path(std::vector<int>, int, int, int, int, int, int, int&)’:
Foo.cpp:273:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
Adding the -Wall flag on your compile will tell the compiler to help you find silly mistakes. I'd fix these warnings and see if your problem goes away.
Related
So I am attempting to complete an assignment using 2d pointer arrays. I was going through the process when I realized that was one of the requirements was that I was supposed to use pointer arithmetic, but instead I have been using offset notation. So my question for you guys is what is the best method of converting my offset notation into pointer arithmetic without completely rewriting the program??? Also when transversing through my 2d array what parameters do I call for my outofbounds function in order for it to properly work? Any suggestions would be greatly appreciated and thank you in advance.
//move through string by parsing to insert each char into array element position
void rules(char** boardArr,int &rows, fstream inFile, string &line, int &cols)
{
char* pos;
char ncount;
for(int i = 0; i < rows; i++) //rows
{
getline(inFile, line);
for(int j = 0; j < cols; j++) //cols
{
*(*(boardArr + i )+ j) == pos;//parsing string into bArr
//neighbor check nested for organism
pos = *(*(boardArr + i)+ j);//position of index within
if(*(*(boardArr + i+1)+ j)=='*')//checking pos to the right of pos index
{
//outofbounds()
ncount++;
}
if(*(*(boardArr + i-1)+ j)=='*')//checking pos to the left of pos index
{
//outofbounds()
ncount++;
}
if(*(*(boardArr + i)+ j+1)=='*')//checking pos to the above of pos index
{
//outofbounds()
ncount++;
}
if(*(*(boardArr + i+1)+ j+1)=='*')//checking pos to the above and to the right of pos index
{
//outofbounds()
ncount++;
}
if(*(*(boardArr + i-1)+ j+1)=='*')//checking pos above and to the left of pos index
{
//outofbounds()
ncount++;
}
if(*(*(boardArr + i-1)+ j-1)=='*')//checking pos below and to the left of pos index
{
//outofbounds()
ncount++;
}
if(*(*(boardArr + i-1)+ j)=='*')//checking pos below of pos index
{
//outofbounds()
ncount++;
}
if(*(*(boardArr + i-1)+ j+1)=='*')//checking pos below and to the right of pos index
{
//outofbounds()
ncount++;
}
//row[i, row[i]-1])
//cout<<*(*(boardArr + i)+ j);//assigning position to check for neighbors
}
}
//how to move through 2d array pointer arithmetic style
//boardArr[rows][cols] == *(*(boardArr + rows)+ cols)
//keep relationship between the numbers
//*(())
//If a cell contains an organism and has fewer than 2 neighbors, the organism dies of loneliness.
//A neighbor is an organism in one of the 8 spots (or fewer if on the edge) around a cell
//If a cell contains an organism and has more than 3 neighbors, it dies from overcrowding.
// If an empty location has exactly three neighbors, an organism is born in that location.
//returns nothing
}
bool outofbounds( int &rows, int &cols, int i, int j)
{
if((i >0 && i< rows) && (j < cols && j > 0))
{
return true;
}
else
return false;
}
There are no reasons to use pointer arithmetics for such simple operations.
Just use arr[i][j] to read/write data.
Also you should check for bounds before any read/write operations to the memory. It is dangerous and may crash your program.
Here is my version of How I'll implement such stuff.
#include <iostream>
/* it is good practice to move functions with special context to classes */
class SafeCharMatrix
{
private:
/* your board */
/* `char const* const*` provides that nobody can change data */
char const* const* _ptr;
int _rows;
int _cols;
public:
SafeCharMatrix(char const* const* ptr, int rows, int cols) :
_ptr(ptr), _rows(rows), _cols(cols)
{}
/* valid check bounds algorithm */
bool CheckBounds(int x, int y) const
{
if (x < 0 || x >= _cols)
return false;
if (y < 0 || y >= _rows)
return false;
return true;
}
bool CheckCharSafe(int x, int y, char c) const
{
/* check bounds before read/write acces to memory */
if (!CheckBounds(x, y))
return false;
return _ptr[x][y] == c;
}
int CountNeighborsSafe(int x, int y, char c) const
{
int count = 0;
count += CheckCharSafe(x - 1, y - 1, c) ? 1 : 0;
count += CheckCharSafe(x - 1, y , c) ? 1 : 0;
count += CheckCharSafe(x - 1, y + 1, c) ? 1 : 0;
count += CheckCharSafe(x , y - 1, c) ? 1 : 0;
/* ignore center (x, y) */
count += CheckCharSafe(x , y + 1, c) ? 1 : 0;
count += CheckCharSafe(x + 1, y - 1, c) ? 1 : 0;
count += CheckCharSafe(x + 1, y , c) ? 1 : 0;
count += CheckCharSafe(x + 1, y + 1, c) ? 1 : 0;
return count;
}
};
/* fill you board before this */
void rules(char const* const* boardArr, int rows, int cols)
{
SafeCharMatrix matrix(boardArr, rows, cols);
for (int i = 0; i < rows; ++i) /* y axis */
{
for (int j = 0; j < cols; ++j) /* x axis */
{
int countOfNeighbors = matrix.CountNeighborsSafe(j, i, '*');
/* do whatever you want */
std::cout
<< "x: " << j << ", "
<< "y: " << i << ", "
<< "count: " << countOfNeighbors << "\n";
}
}
}
/* just example of how it can works */
int main()
{
char r1[3] = { 0 , 0 , '*'};
char r2[3] = { 0 , 0 , 0 };
char r3[3] = { '*', 0 , 0 };
char* m[3];
m[0] = r1;
m[1] = r2;
m[2] = r3;
rules(m, 3, 3);
}
Edit:
Don't pass simple arguments like int numbers by reference: int &row. They are to small and compiler can pack them in just one processor register.
Given a number S ( int > 0 ) and n (int > 0), print all the different subsets of len n which sum to S.
For S = 7 and n = 3, the output is the following, the output must be descending order:
5 + 1 + 1
4 + 2 + 1
3 + 3 + 1
3 + 2 + 2
Here is what I've tried so far:
vector<vector<int> > partitions(int X, int Y)
{
vector<vector<int> > v;
if (X <= 1 && X <= X - Y + 1)
{
v.resize(1);
v[0].push_back(X);
return v;
}
for (int y = min(X - 1, Y); y >= 1; y--)
{
vector<vector<int> > w = partitions(X - y, y);
for (int i = 0; i<w.size(); i++)
{
w[i].push_back(y);
v.push_back(w[i]);
}
}
return v;
}
int main()
{
vector<vector<int> > v = partitions(7, 3);
int i;
for (i = 0; i<v.size(); i++)
{
int x;
for (x = 0; x<v[i].size(); x++)
printf("%d ", v[i][x]);
printf("\n");
}
}
the first element in the matrix is s- n + 1 and full of 1 till the sum is reached, or if the s-n+1 is equal to s, then n is 1, so only s will be the solution.
p.s.: I don t know if this problem has a particular name
This may not be the best solution for your problem, since it's not a dynamic programming based solution. In this case, I'm using recursion to fill an array until I reduce the desired number to 0. In this solution, every combination will be stored in the increasing order of the elements so we prevent permutations of a already calculated solution.
#include <iostream>
void findCombinationGivenSize(int numbersArray[], int index, int num, int reducedNum, int maxNum){
if (reducedNum < 0)
return; // this is our base case
if (reducedNum == 0 && index == maxNum){ // both criteria were attended:
//the sum is up to num, and the subset contain maxNum numbers
for (int i = index - 1; i>=0; i--)
std::cout<< numbersArray[i] << " + ";
// here we will have a problem with an extra '+' on the end, but you can figure out easily how to remove it :)
std::cout<<std::endl;
return;
}
// Find the previous number stored in arrayNumber[]
int prev;
if(index == 0)
prev = 1;
else
prev = numbersArray[index-1];
for (int k = prev; k <= num; k++){
// next element of array is k
numbersArray[index] = k;
// call recursively with reduced number
findCombinationGivenSize(numbersArray, index + 1, num,reducedNum - k, maxNum);
}
}
void findCombinations(int number, int maxSubset){
int arrayNumbers[number];
findCombinationGivenSize(arrayNumbers, 0, number, number, maxSubset);
}
int main(){
int number = 7;
int maxPartitions = 3;
findCombinations(number, maxPartitions);
return 0;
}
I'm currently studying for an exam and I'm trying to deal with dynamical matrix. I've come across a problem regarding calculating the sum of every diagonal of a matrix whose values and size are chosen by the user.
The intent of my program is to print, thanks to a function, whose parameters are the matrix and its size, the value of every diagonal sum. I'll show you the code and describe it in depth.
----------------
| 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".
This is what I thought to do, according to my description:
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
Obviously it does not work, but I can't figure out the problem.
(There used to be a paragraph here, but on a second look, you didn’t make the mistake it was talking about.)
Since you didn’t post to Code Reviews, here’s a solution instead of a detailed code review. (If you want to make the original approach work, I’d suggest single-stepping through it in a debugger and checking where your variables first get the wrong value.) It’s got a lot of boilerplate to make it compile and run, but the part you’ll be most interested in is diag_sums() and its comments.
One idea here is to use OOP to automatically check the bounds of your array accesses. The latter is very important for catching off-by-one errors and the like. You can turn it off in production if you want, but you really don’t want to silence warnings when your program has a buffer overrun. Other optimizations here include locality of access for the data, and strength reduction on the operations: rather than check on each iteration whether we’ve hit the right edge and the bottom edge, we can simply calculate the length of each diagonal in advance.
Since the definition of diagonal number k of matrix a with M rows is equivalent to: all elements a[i][j] such that such that M - k = i - j, the algorithm ensures correctness by maintaining the invariant, which holds whenever we add 1 to both i and j, starting when either i or j is 0, and stopping whenever i = M or j = N, that is, traversing each step of the diagonal from the left or top edge to the right or bottom edge, whichever comes first.
#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;
}
You could also just do print_sequence(diag_sums(read_input_matrix( rows, columns ))).
You can simplify your code finding the starting position of each diagonal and then stepping through the matrix as long as the coordinates stay inside the matrix.
Something like this:
#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;
}
I would like to create a function which initializes a vector or array of size width * height, but which also creates a border around these values.
The values around the outside also need to be initialized to a different value from the ones in the center.
The objects I am storing do not have a default constructor, so I cannot rely on that for initialization.
This is the code I have so far, but it feels like there should be a simpler or more idiomatic way of doing this.
I can use any features up to and including C++1z.
#include <iostream>
#include <vector>
void fill_values(const unsigned width, const unsigned height, std::vector<int> &values) {
for(unsigned y=0; y<height+2; ++y) {
for(unsigned x=0; x<width+2; ++x) {
if(x==0 || x==width+1 || y==0 || y==height+1) {
values.push_back(1);
} else {
values.push_back(0);
}
}
}
}
int main(int argc, char *argv[]) {
const unsigned width = 4;
const unsigned height = 3;
std::vector<int> values;
fill_values(width, height, values);
for(unsigned y=0; y<height+2; ++y) {
for(unsigned x=0; x<width+2; ++x) {
std::cout << values[y * (width+2) + x];
}
std::cout << '\n';
}
return 0;
}
Output : -
111111
100001
100001
100001
111111
Honestly, your code is fine. I pretty easily understood what it does.
But in the spirit of proposing alternate complex implementations, I'd propose the following. A different way to fill the matrix is to add a full row of 1s, then height rows of 1000...001, then another full row of 1s. We can make that a bit more explicit. Also, would suggest returning a vector instead of filling it:
std::vector<int> fill_values(const unsigned width, const unsigned height) {
std::vector<int> m;
m.reserve((width + 2) * (height + 2));
// add row of 1s
m.insert(m.end(), width + 2, 1);
// add height middle rows
for (int i = 0; i < height; ++i) {
m.push_back(1);
m.insert(m.end(), width, 0);
m.push_back(1);
}
// and a final row of 1s
m.insert(m.end(), width + 2, 1);
return m;
}
As #Fedorico said in the comments, using a vector of vectors is a better representation for your values variable. Rather than pass the values by reference as a parameter, it would be better to depend on copy elision for the return value. I also found it easier to just use the set height and width to be the total number of rows and cols in the data so that there's no need to add two.
The following code depends on c++11 or newer:
#include <iostream>
#include <vector>
using namespace std;
// Fills the 2D matrix with 1s on the border and 0s in the middle.
vector<vector<int>> generate_matrix(int rows, int cols);
void print_matrix(const vector<vector<int>>& matrix);
int main()
{
// Don't sync I/O with C stdio.
ios_base::sync_with_stdio(false);
// Height and Width of the entire 2D matrix.
const int rows = 6;
const int cols = 5;
vector<vector<int>> matrix = generate_matrix(rows, cols);
print_matrix(matrix);
return 0;
}
vector<vector<int>> generate_matrix(int rows, int cols)
{
// fill a rows x cols 2D vector with 0s.
vector<vector<int>> matrix(rows, vector<int>(cols, 0));
// fill in 1s on top and bottom rows.
if (rows > 0)
{
for (int i = 0; i < cols; ++i)
{
matrix[0][i] = 1;
matrix[rows-1][i] = 1;
}
}
// fill in 1s on the left and right columns.
if (cols > 0)
{
for (int i = 0; i < rows; ++i)
{
matrix[i][0] = 1;
matrix[i][cols-1] = 1;
}
}
return matrix;
}
void print_matrix(const vector<vector<int>>& matrix)
{
// Use a reference for the row iterator to prevent a vector copy.
for (auto& row : matrix)
{
for (auto element : row)
{
cout << element;
}
cout << '\n';
}
}
Not a great difference, but you can use std::generate_n() (starting from c++11) with a lambda function.
The following is a full working example
#include <vector>
#include <iostream>
#include <algorithm>
int main ()
{
constexpr std::size_t width { 4U };
constexpr std::size_t height { 3U };
constexpr std::size_t w2 { width + 2U };
constexpr std::size_t h2 { height + 2U };
std::vector<int> values;
values.resize ( w2 * h2 );
std::generate_n(values.begin(), w2 * h2, [=]() -> int
{
static std::size_t i = -1;
++i;
return ( 0U == i / w2 ) || ( h2 - 1U == i / w2 )
|| ( 0U == i % w2 ) || ( w2 - 1U == i % w2 );
});
for(unsigned y=0; y<height+2; ++y) {
for(unsigned x=0; x<width+2; ++x) {
std::cout << values[y * (width+2) + x] << ' ';
}
std::cout << '\n';
}
return 0;
}
If width and heigth are known at compile time, you can initialize the std::vector (or the std::array?) with initializer list, using a little template work (give me some time and I'll show an example).
The scatter method takes the original image and scatter its pixels.
The program works well when I use several lines of code instead of the
method "randomSelect". The program seems to go into an infinite loop
and the image does not change when I use the method "randomSelect".
void scatter(GBufferedImage &img, Grid<int> original, int row, int col) {
int degree;
while (true) {
degree = getInteger("Enter degree of scatter [1-100]: ");
if (degree >=1 && degree <= 100) break;
}
Grid<int> newImg(row, col);
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
/* int newRow = -1;
int newCol = -1;
while (!original.inBounds(newRow, newCol)) {
newRow = randomInteger(max(i - degree, 0), min(i + degree,original.numRows()));
newCol = randomInteger(max(j - degree, 0), min(j + degree,original.numRows()));
}
newImg[i][j] = original[newRow][newCol]; */ // work properly
newImg[i][j] = randomSelect(original, i , j, degree); // do not work
}
}
img.fromGrid(newImg);
}
int randomSelect(Grid<int> original, int i, int j, int degree) { // do not work
int newRow = -1;
int newCol = -1;
while (!original.inBounds(newRow, newCol)) {
newRow = randomInteger(max(i - degree, 0), min(i + degree,original.numRows()));
newCol = randomInteger(max(j - degree, 0), min(j + degree,original.numRows()));
}
return original[newRow][newCol];
}
You should pass original as a reference:
int randomSelect(Grid<int>& original, int i, int j, int degree) { // will work