Related
As a homework, I have a problem which sounds like this:
We have a n*n square matrix. It is called 'subdiagonal'
if all the elements above the main diagonal are null.
a) Copy the useful elements (the ones which are not null, so basically all the elements
from the main diagonal and below) to an array. (I've done that)
b) Write an algorithm which takes two subdiagonal matrix A, B as an input.
Those are transformed into arrays V_a and V_b with the algorithm from a),
then they calculate C = A*B only using only V_a and V_b
e.g.
Let's say A =
1 0 0 0 0
2 3 0 0 0
4 1 3 0 0
1 9 0 2 0
1 0 1 2 2
B =
2 0 0 0 0
1 1 0 0 0
0 1 2 0 0
1 1 2 3 0
2 0 0 1 2
after this input, V_a = 1,2,3,4,1,3,1,9,0,2,1,0,1,2,2; V_b = 2,1,1,0,1,2,1,1,2,3,2,0,0,1,2
and the product V_c will be 2,7,3,9,4,6,13,11,4,6,8,3,6,8,4
so the matrix will look like
2 0 0 0 0
7 3 0 0 0
9 4 6 0 0
13 11 4 6 0
8 3 6 8 4
Here's the code that I've been working on for a while:
#include <iostream>
#include <algorithm>
void read(int& a, int**& matrix)
{
std::cin >> a;
matrix = new int*[a];
for (int i = 0; i < a; i++)
{
for (int j = 0; j < a; j++)
{
matrix[i] = new int[a];
}
}
for (int i = 0; i < a; i++)
{
for (int j = 0; j < a; j++)
{
std::cin >> matrix[i][j];
}
}
}
void showMatrix(int a, int** matrix)
{
for (int i = 0; i < a; i++)
{
for (int j = 0; j < a; j++)
{
std::cout << matrix[i][j] << " ";
}
std::cout << std::endl;
}
}
void showArray(int a, int* array)
{
for (int i = 0; i < a; i++)
{
std::cout << array[i] << " ";
}
}
void createArray(int a, int& arrayLength, int** matrix, int*& array)
{
int nrDeElemente = a*a - (a * (a - 1)) / 2;
array = new int[nrDeElemente+1];
arrayLength = 0;
for (int i = 0; i < a; i++)
{
for (int j = 0; j < i+1; j++)
{
array[arrayLength++] = matrix[i][j];
}
}
}
int* multiplyArrays(int a, int arrayLength, int* array1, int* array2)
{
int* array3 = new int[arrayLength + 1];
for (int i = 0; i < a; i++)
{
array3[i] = 0;
}
int t = 1;
for (int i = 0; i < arrayLength; ++i)
{
for (int j = 0; j < t; ++j)
{
for (int p = j; p < a; p++)
{
array3[i] += array1[j] * array2[p];
}
}
++t;
}
return array3;
}
int main()
{
int **matrix1, **matrix2;
int *array1, *array2, *multiplyResult;
int a, arrayLength;
read(a, matrix1);
read(a, matrix2);
createArray(a, arrayLength, matrix1, array1);
createArray(a, arrayLength, matrix2, array2);
multiplyResult = multiplyArrays(a, arrayLength, array1, array2);
showArray(arrayLength, multiplyResult);
}
I've done a), but I don't know how to do b)
I think I understood it (after many hours of trials) conceptually, but I don't really know how to implement it.
I need 3 for loops, as such:
->the most outer one has to be responsible for the position we calculate on the new array
->the next one has to choose which elements from the second array will be multiplied. (choose the multiplier) That's one of
the loops I don't know how to implement. It somehow has to stop when the line (from the matrix) ended and start where it stopped + 1 element.
->the most inner one has to choose the second term of the multiplication (the multiplicand).
I also don't know how I should implement this one. It should choose as many elements as there multipliers are and also, the looping is quite strange (because I need to select all the elements from the same row every time).
Can anybody help me solve point b and also explain their thinking?
I struggled a lot and I really feel like I need help.
BTW the 3 for loops from multiplyArrays make no sense, you can just write something else instead of them. Those 3 for loops are basically the only things that my program needs (I think).
Thanks :)
Matrix multiplication C = A*B is defined by C(i,j) = sum_k A(i,k)*B(k,j). The matrix A has structural nonzeros where i >= k, and B, where k >= j. Thus it suffices to iterate
(outer loop) i from 0 to n-1
(middle) j from 0 to i
(inner) k from j to i.
The other piece is turning coordinates (i,j) into an offset with respect to the 1D storage format. The number of structural nonzeros in the first i rows is given by the ith triangular number, (i+1)*i/2. Hence the jth element in this row is at (zero-based) index (i+1)*i/2 + j. You or your compiler can strength-reduce the multiplication.
To multiply matrices requires to find where a row start in array, for example row[2] starts at index 3 in array as highlighted below,
1 0 0 0 0
2 3 0 0 0
4 1 3 0 0 => row[2]
1 9 0 2 0
1 0 1 2 2
[1, 2, 3, 4, 1, 3, 1, 9, 0, 2, 1, 0, 1, 2, 2]
Any row can be found if we know how may elements are present before it, like in above example if we know that three elements are present before row[2] then we can locate row[2] easily.
To find number of elements presents before each row requires to calculated an auxiliary array of size equals to number of rows, but to do that let's first see matrix again,
As you can see each row contains element equal to the index + 1 of row,
1 element count = index + 1 = 0 + 1 = 1
2 3 = 1 + 1 = 2
4 1 3 = 2 + 1 = 3
1 9 0 2 ..
1 0 1 2 2 ..
It means our auxiliary array would be,
auxiliary array = [0, 1, 2, 3, 4] but how ?
As we know there are no element before row[0] that's why auxiliaryArray[0] = 0 then elements before row[1] is only one element which can be found by index of previous row that is previous row index + 1 => 0 + 1 as showed above auxiliaryArray[1] = 1 and similar for all rows,
But it is not done! current state of auxiliary array is only having information about number of elements present in immediate previous row but not in all previous rows, and to do so we have to calculate sum of all previous rows and that is called partial sum and it will be done as follows,
row[0] = row[0]
row[1] = row[0] + row[1]
row[2] = row[1] + row[2]
..
..
and final result,
auxiliary array = [0, 1, 3, 6, 10]
So as you can see number of elements before row[2] = auxiliaryArray[2] = 3
By using above auxiliary array you can locate any row and if you get first element of row you can find all col elements.
Next point to understand is how many elements you have to multiply in each row and that is again number of elements to multiply = index + 1 as you see above in matrix row[0] only have one element to multiple index + 1 => 0 + 1 and same rule apply for each row.
Last point to consider is, when row is multiplied with col of other matrix it doesn't start always with row[0] of other matrix as you can see below otherMatrix[0][1] is outside of left diagonal of other matrix,
2 0 0 0 0
1 1 0 0 0
0 1 2 0 0
1 1 2 3 0
2 0 0 1 2
Finally we are done!
#include <iostream>
#include <vector>
#include <numeric>
#include <iterator>
using std::cout;
void printMatrixArray(std::size_t rowSize, const std::vector<int>& matArray){
std::size_t elementCount = 1;
std::vector<int>::const_iterator it = matArray.cbegin();
for(std::size_t row = 0; row < rowSize; ++row){
std::copy(it, it + elementCount, std::ostream_iterator<int>(cout, "\t"));
cout<< '\n';
it += elementCount;
++elementCount;
}
}
std::vector<int> leftDiagonalBottomMatrix(const std::vector<std::vector<int>>& mat){
std::vector<int> res;
res.reserve(((1 + mat.size()) * mat.size()) / 2);
std::vector<int>::size_type elementCount = 1;
for(const std::vector<int>& row : mat){
for(std::vector<int>::const_iterator it = row.cbegin(), endIt = row.cbegin() + elementCount; endIt != it; ++it){
res.push_back(*it);
}
++elementCount;
}
return res;
}
std::vector<int> multiplyMatrixArrays(const std::vector<int>& mat1Arr, const std::vector<int>& mat2Arr,
std::vector<int>::size_type rowSize){
std::vector<int> auxiliaryArray(rowSize);
auxiliaryArray.front() = 0;
std::iota(auxiliaryArray.begin() + 1, auxiliaryArray.end(), 1);
std::partial_sum(auxiliaryArray.cbegin(), auxiliaryArray.cend(), auxiliaryArray.begin());
std::vector<int> res;
res.reserve(mat1Arr.size());
for(std::vector<int>::size_type row = 0; row < rowSize; ++row){
for(std::vector<int>::size_type col = 0; col <= row; ++col){
int val = 0;
for(std::vector<int>::size_type ele = col, elementCount = row + 1; ele < elementCount; ++ele){
val += mat1Arr[auxiliaryArray[row] + ele] * mat2Arr[auxiliaryArray[ele] + col];
}
res.push_back(val);
}
}
return res;
}
std::vector<int> matrixMultiply(const std::vector<std::vector<int>>& mat1, const std::vector<std::vector<int>>& mat2){
return multiplyMatrixArrays(leftDiagonalBottomMatrix(mat1), leftDiagonalBottomMatrix(mat2), mat1.size());
}
int main(){
std::vector<std::vector<int>> mat1{{1, 0, 0, 0, 0}, {2, 3, 0, 0, 0}, {4, 1, 3, 0, 0}, {1, 9, 0, 2, 0},
{1, 0, 1, 2, 2}};
std::vector<std::vector<int>> mat2{{2, 0, 0, 0, 0}, {1, 1, 0, 0, 0}, {0, 1, 2, 0, 0}, {1, 1, 2, 3, 0},
{2, 0, 0, 1, 2}};
printMatrixArray(mat1.size(), matrixMultiply(mat1, mat2));
}
Output:
2
7 3
9 4 6
13 11 4 6
8 3 6 8 4
Output does not print elements above the left diagonal of matrix!
I have a 2d array like this:
arr = [0 3 1 0
1 2 0 2
0 0 2 0
1 2 0 0]
My aim is don't iterate over a column once we find maximum number in it.
In the first iteration, max number is 3 in 2nd column, so don't go to second column in future iterations.
Similarly in my 2nd iteration, max number is 2 in 4th column (Because we dont go to 2nd column anymore).
This is what i tried:
#include <iostream>
using namespace std;
int main()
{
//Input 2d array
int arr[4][4];
//Take the input
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
cin>>arr[i][j];
}
//Index array to store index of maximum number column
int index[4] = {-1,-1,-1,-1}
//Array to store max number in each row
int max_arr[4] = {0,0,0,0};
for(int i=0; i<4; i++)
{
int max_num = -1;
for(int j=0; j<4; j++)
{
if(j!=index[0] && j!=index[1] && j!=index[2] && j!=index[3])
{
if(max_num<arr[i][j])
{
max_num = arr[i][j];
index[j] = j;
}
}
}
max_arr[i] = max_num;
}
return 0;
}
The best way to go about this is to simply evaluate the array by columns. This can be done with a little math. In your case, you use a 4x4 array. Start at index 0, add 4, add 4, add 4, then subtract 11 (bringing you to position 1). Add 4, add 4, add 4, subtract 11 (bringing you to position 2). Etc...
Here is the code I used, which works and is doable for any size array!
#include <iostream>
int main()
{
constexpr size_t ARR_ROWS = 4;
constexpr size_t ARR_COLS = 4;
constexpr size_t ARR_SIZE = ARR_ROWS * ARR_COLS;
int arr[ARR_SIZE] {
0, 3, 1, 0,
1, 2, 0, 2,
0, 0, 2, 0,
1, 2, 0, 0
};
// Store max values for columns
int cols_max[ARR_COLS] { -1, -1, -1, -1 };
// Start at index 0, then at 4 (3 times) to evaluate first
// column. Next, subtract 11 from current index (12) to get
// to index 1 (start of column 2). Add 4 (3 times) to
// evaluate second column. Next, subtract 11 from current
// index (13) to get to index 2 (start of column 3). Etc...
size_t cur_index = 0;
size_t cur_col = 0;
const size_t subtract_to_start_next_col = ARR_SIZE - (ARR_COLS + 1);
while (cur_index < ARR_SIZE)
{
// Max function for 'cols_max'
if (cols_max[cur_col] < arr[cur_index])
cols_max[cur_col] = arr[cur_index];
if ( // When index is at the column's end (besides last value)
(cur_index >= ARR_SIZE - ARR_COLS) &&
(cur_index <= ARR_SIZE - 2)
)
{
cur_index -= subtract_to_start_next_col;
cur_col++;
}
else if (cur_index == ARR_SIZE - 1)
{ // When index is last value, add 1 to break loop
cur_index++;
}
else
{ // Nothing special, just go to next value in column
cur_index += ARR_COLS;
}
}
// Print columns' max values (optional)...
for (size_t i = 0; i < ARR_COLS; ++i)
{
std::cout
<< "Max for column " << (i + 1) << ": " << cols_max[i]
<< std::endl;
}
}
Feel free to ask if you have any questions!
You need 3 loops, first for iterations, second for rows, third for columns. If you have found max at column let's say 0, then you should blacklist that column and so on.
#include <iostream>
int main()
{
int m[ 4 ][ 4 ] = { { 0, 3, 1, 0 } ,
{ 1, 2, 0, 2 } ,
{ 0, 0, 2, 0 } ,
{ 1, 2, 0, 0 } };
constexpr int max_number_of_itr { 4 };
bool blacklisted[4] { false };
for ( auto itr = 0; itr < max_number_of_itr; ++itr )
{
auto max { -1 };
auto max_col_idx { -1 };
for ( auto row = 0; row < 4; ++row )
{
for ( auto col = 0; col < 4; ++col )
{
if ( blacklisted[ col ] )
continue;
auto val = m[ row ][ col ];
if ( val > max )
{
max = val;
max_col_idx = col;
}
}
}
blacklisted[ max_col_idx ] = true;
std::cout << "max is " << max << " col " << max_col_idx << " ignored." << std::endl;
}
}
index[ j ] = j;
change this to
index[ i ] = j;
I have a table of numbers that look like this:
2 8 4 0
3 1 0 9
1 2 3 4
5 4 14 2
I put all the numbers in an array { 2,8,4,0,3,1... }. Is there a way to sort it by the first column only using a 1D array so that it ends up like this:
1 2 3 4
2 8 4 0
3 1 0 9
5 4 14 2
I know there's a way of doing it with a 2D array, but, assuming I know the number of columns, is it possible with only a 1D array?
I'd create an array of indexes into your data, and then sort those indexes; this will save a decent number of the copies.
Your sort would then examine the value of the number at the given index.
ie for your example - indexes would be 1,2,3,4
and then sorted would read 3,1,2,4
edit: this was 1 based; the code 0 based. Makes no difference.
Essentially converting your 1d array into 2. Since the bulk of your data is still contiguous (especially for large numbers of columns) reading should still be fast.
Example code:
std::vector<int> getSortedIndexes(std::vector<int> data, int size) {
int count = data.size() / size;
std::vector<int> indexes(count);
// fill in indexes from 0 to "count" since that's the size of our vector
std::iota(indexes.begin(), indexes.end(), 0);
// don't write your own sorting implementation .... really; don't.
std::sort(indexes.begin(), indexes.end(), [data, size](int indexA, int indexB) {
return data[indexA*size] < data[indexB*size];
});
return indexes;
}
For arrays of non-user defined types it is easy to do the task using the standard C function qsort.
Here is a demonstrative program.
#include <iostream>
#include <cstdlib>
int cmp( const void *a, const void *b )
{
const int *left = static_cast<const int *>( a );
const int *right = static_cast<const int *>( b );
return ( *right < *left ) - ( *left < *right );
}
int main()
{
const size_t N = 4;
int a[N * N] =
{
2, 8, 4, 0, 3, 1, 0, 9, 1, 2, 3, 4, 5, 4, 14, 2
};
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
std::cout << a[N * i + j] << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
std::qsort( a, N, sizeof( int[N] ), cmp );
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
std::cout << a[N * i + j] << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
}
The program output is
2 8 4 0
3 1 0 9
1 2 3 4
5 4 14 2
1 2 3 4
2 8 4 0
3 1 0 9
5 4 14 2
So all you need is to write the function
int cmp( const void *a, const void *b )
{
const int *left = static_cast<const int *>( a );
const int *right = static_cast<const int *>( b );
return ( *right < *left ) - ( *left < *right );
}
and add just one line in your program
std::qsort( a, N, sizeof( int[N] ), cmp );
You can use bubblesort:
void sort_by_name(int* ValueArray, int NrOfValues, int RowWidth)
{
int CycleCount = NrOfValues / RowWidth;
int temp;
(int j = 0; j < CycleCount ; j++)
{
for (int i = 1; i < (CycleCount - j); i++)
{
if(ValueArray[((i-1)*RowWidth)] > ValueArray[(i*RowWidth)])
{
for(int k = 0; k<RowWidth; k++)
{
temp = ValueArray[(i*RowWidth)+k]
ValueArray[(i*RowWidth)+k] = ValueArray[((i-1)*RowWidth)+k];
ValueArray[((i-1)*RowWidth)+k] = temp;
}
}
}
}
}
keep in mind that simply making your array 2D will be a MUCH BETTER solution
edit: variable naming
There is a problem where I need to fill an array with zeros, with the following assumptions:
in the array there can only be 0 and 1
we can only change 0 to 1 and 1 to 0
when we meet 1 in array, we have to change it to 0, such that its neighbours are also changed, for instance, for the array like the one below:
1 0 1
1 1 1
0 1 0
When we change element at (1,1), we then got the array like this:
1 1 1
0 0 0
0 0 0
We can't change the first row
We can only change the elements that are in the array
The final result is the number of times we have to change 1 to 0 to zero out the array
1) First example, array is like this one below:
0 1 0
1 1 1
0 1 0
the answer is 1.
2) Second example, array is like this one below:
0 1 0 0 0 0 0 0
1 1 1 0 1 0 1 0
0 0 1 1 0 1 1 1
1 1 0 1 1 1 0 0
1 0 1 1 1 0 1 0
0 1 0 1 0 1 0 0
The answer is 10.
There also can be situations that its impossible to zero out the array, then the answer should be "impossible".
Somehow I can't get this working: for the first example, I got the right answer (1) but for the second example, program says impossible instead of 10.
Any ideas what's wrong in my code?
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
int n,m;
cin >> n >> m;
bool tab[n][m];
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
cin >> tab[i][j];
int counter = 0;
for(int i=0; i<n-1; i++)
{
for(int j=0; j<m-1; j++)
{
if(tab[i][j] == 1 && i > 0 && j > 0)
{
tab[i-1][j] = !tab[i-1][j];
tab[i+1][j] = !tab[i+1][j];
tab[i][j+1] = !tab[i][j+1];
tab[i][j-1] = !tab[i][j-1];
tab[i][j] = !tab[i][j];
counter ++;
}
}
}
bool impossible = 0;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(tab[i][j] == 1)
{
cout << "impossible\n";
impossible = 1;
break;
}
}
if(impossible)
break;
}
if(!impossible)
cout << counter << "\n";
return 0;
}
I believe that the reason your program was returning impossible in the 6x8 matrix is because you have been traversing in a left to right / top to bottom fashion, replacing every instance of 1 you encountered with 0. Although this might have seemed as the right solution, all it did was scatter the 1s and 0s around the matrix by modifying it's neighboring values. I think that the way to approach this problem is to start from bottom to top/ right to left and push the 1s towards the first row. In a way cornering (trapping) them until they can get eliminated.
Anyway, here's my solution to this problem. I'm not entirely sure if this is what you were going after, but I think it does the job for the three matrices you provided. The code is not very sophisticated and it would be nice to test it with some harder problems to see if it truly works.
#include <iostream>
static unsigned counter = 0;
template<std::size_t M, std::size_t N>
void print( const bool (&mat) [M][N] )
{
for (std::size_t i = 0; i < M; ++i)
{
for (std::size_t j = 0; j < N; ++j)
std::cout<< mat[i][j] << " ";
std::cout<<std::endl;
}
std::cout<<std::endl;
}
template<std::size_t M, std::size_t N>
void flipNeighbours( bool (&mat) [M][N], unsigned i, unsigned j )
{
mat[i][j-1] = !(mat[i][j-1]);
mat[i][j+1] = !(mat[i][j+1]);
mat[i-1][j] = !(mat[i-1][j]);
mat[i+1][j] = !(mat[i+1][j]);
mat[i][j] = !(mat[i][j]);
++counter;
}
template<std::size_t M, std::size_t N>
bool checkCornersForOnes( const bool (&mat) [M][N] )
{
return (mat[0][0] || mat[0][N-1] || mat[M-1][0] || mat[M-1][N-1]);
}
template<std::size_t M, std::size_t N>
bool isBottomTrue( bool (&mat) [M][N], unsigned i, unsigned j )
{
return (mat[i+1][j]);
}
template<std::size_t M, std::size_t N>
bool traverse( bool (&mat) [M][N] )
{
if (checkCornersForOnes(mat))
{
std::cout<< "-Found 1s in the matrix corners." <<std::endl;
return false;
}
for (std::size_t i = M-2; i > 0; --i)
for (std::size_t j = N-2; j > 0; --j)
if (isBottomTrue(mat,i,j))
flipNeighbours(mat,i,j);
std::size_t count_after_traversing = 0;
for (std::size_t i = 0; i < M; ++i)
for (std::size_t j = 0; j < N; ++j)
count_after_traversing += mat[i][j];
if (count_after_traversing > 0)
{
std::cout<< "-Found <"<<count_after_traversing<< "> 1s in the matrix." <<std::endl;
return false;
}
return true;
}
#define MATRIX matrix4
int main()
{
bool matrix1[3][3] = {{1,0,1},
{1,1,1},
{0,1,0}};
bool matrix2[3][3] = {{0,1,0},
{1,1,1},
{0,1,0}};
bool matrix3[5][4] = {{0,1,0,0},
{1,0,1,0},
{1,1,0,1},
{1,1,1,0},
{0,1,1,0}};
bool matrix4[6][8] = {{0,1,0,0,0,0,0,0},
{1,1,1,0,1,0,1,0},
{0,0,1,1,0,1,1,1},
{1,1,0,1,1,1,0,0},
{1,0,1,1,1,0,1,0},
{0,1,0,1,0,1,0,0}};
std::cout<< "-Problem-" <<std::endl;
print(MATRIX);
if (traverse( MATRIX ) )
{
std::cout<< "-Answer-"<<std::endl;
print(MATRIX);
std::cout<< "Num of flips = "<<counter <<std::endl;
}
else
{
std::cout<< "-The Solution is impossible-"<<std::endl;
print(MATRIX);
}
}
Output for matrix1:
-Problem-
1 0 1
1 1 1
0 1 0
-Found 1s in the matrix corners.
-The Solution is impossible-
1 0 1
1 1 1
0 1 0
Output for matrix2:
-Problem-
0 1 0
1 1 1
0 1 0
-Answer-
0 0 0
0 0 0
0 0 0
Num of flips = 1
Output for matrix3:
-Problem-
0 1 0 0
1 0 1 0
1 1 0 1
1 1 1 0
0 1 1 0
-Found <6> 1s in the matrix.
-The Solution is impossible-
0 1 1 0
1 0 1 1
0 0 0 0
0 0 0 1
0 0 0 0
Output for matrix4 (which addresses your original question):
-Problem-
0 1 0 0 0 0 0 0
1 1 1 0 1 0 1 0
0 0 1 1 0 1 1 1
1 1 0 1 1 1 0 0
1 0 1 1 1 0 1 0
0 1 0 1 0 1 0 0
-Answer-
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Num of flips = 10
Ok, here comes my somewhat different attempt.
Idea
Note: I assume here that "We can't change the first row" means "We can't change the outmost row".
Some terminology:
With toggling a bit I mean changing it's value from 0 to 1 or 1 to 0.
With flipping a bit I mean toggling said bit and the 4 bits around it.
The act of toggling a bit is commutative. That is, it does not matter in what order we toggle it—the end result will always be the same (this is a trivial statement). This means that flipping is also a commutative action, and we are free to flip bits in any order we like.
The only way to toggle a value on the edge of the matrix is by flipping the bit right next to it an uneven amount of times. As we're looking for the lowest possible flips, we want to flip it a maximum of 1 time. So, in a scenario like the on below, x will need to be flipped exactly once, and y will need to be flipped exactly 0 times.
. .
1 x
0 y
. ,
From this we can draw two conclusions:
A corner of the matrix can never be toggled—if a 1 on the corner is found it is not possible with any number of flips to make the matrix zero. Your first example can thus be discarded without even flipping a single bit.
A bit next to a corner must have the same same value as the bit on the other side. This matrix that you posted in a comment can thus as well be discarded without flipping a single bit (bottom right corner).
Two examples of the conditions above:
0 1 .
0 x .
. . .
Not possible, as x needs to be flipped exactly once and exactly zero times.
0 1 .
1 x .
. . .
Possible, x needs to be flipped exactly once.
Algorithm
We can now make an recursive argument, and I propose the following:
We are given an m by n matrix.
Check the corner conditions above as stated above (i.e. corner != 1, bits next to corner has to be the same value). If either criteria are violated, return impossible.
Go around the edge of the matrix. If a 1 is encountered, flip the closest bit inside, and add 1 to the counter.
Restart now from #1 with a m - 2 by n - 2 matrix (top and bot row removed, left and right column) if either dimension is > 2, otherwise print the counter and quit.
Implementation
Initially I had thought this would turn out nice and pretty, but truth be told it is a little more cumbersome than I originally thought it would be as we have to keep track of a lot of indices. Please ask questions if you're wondering about the implementation, but it is in essence a pure translation of the steps above.
#include <iostream>
#include <vector>
using Matrix = std::vector<std::vector<int>>;
void flip_bit(Matrix& mat, int i, int j, int& counter)
{
mat[i][j] = !mat[i][j];
mat[i - 1][j] = !mat[i - 1][j];
mat[i + 1][j] = !mat[i + 1][j];
mat[i][j - 1] = !mat[i][j - 1];
mat[i][j + 1] = !mat[i][j + 1];
++counter;
}
int flip(Matrix& mat, int n, int m, int p = 0, int counter = 0)
{
// I use p for 'padding', i.e. 0 means the full array, 1 means the outmost edge taken away, 2 the 2 most outmost edges, etc.
// max indices of the sub-array
int np = n - p - 1;
int mp = m - p - 1;
// Checking corners
if (mat[p][p] || mat[np][p] || mat[p][mp] || mat[np][mp] || // condition #1
(mat[p + 1][p] != mat[p][p + 1]) || (mat[np - 1][p] != mat[np][p + 1]) || // condition #2
(mat[p + 1][mp] != mat[p][mp - 1]) || (mat[np - 1][mp] != mat[np][mp - 1]))
return -1;
// We walk over all edge values that are *not* corners and
// flipping the bit that are *inside* the current bit if it's 1
for (int j = p + 1; j < mp; ++j) {
if (mat[p][j]) flip_bit(mat, p + 1, j, counter);
if (mat[np][j]) flip_bit(mat, np - 1, j, counter);
}
for (int i = p + 1; i < np; ++i) {
if (mat[i][p]) flip_bit(mat, i, p + 1, counter);
if (mat[i][mp]) flip_bit(mat, i, mp - 1, counter);
}
// Finished or flip the next sub-array?
if (np == 1 || mp == 1)
return counter;
else
return flip(mat, n, m, p + 1, counter);
}
int main()
{
int n, m;
std::cin >> n >> m;
Matrix mat(n, std::vector<int>(m, 0));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
std::cin >> mat[i][j];
}
}
int counter = flip(mat, n, m);
if (counter < 0)
std::cout << "impossible" << std::endl;
else
std::cout << counter << std::endl;
}
Output
3 3
1 0 1
1 1 1
0 1 0
impossible
3 3
0 1 0
1 1 1
0 1 0
1
6 8
0 1 0 0 0 0 0 0
1 1 1 0 1 0 1 0
0 0 1 1 0 1 1 1
1 1 0 1 1 1 0 0
1 0 1 1 1 0 1 0
0 1 0 1 0 1 0 0
10
4 6
0 1 0 0
1 0 1 0
1 1 0 1
1 1 1 0
1 1 1 0
impossible
If tab[0][j] is 1, you have to toggle tab[1][j] to clear it. You then cannot toggle row 1 without unclearing row 0. So it seems like a reduction step. You repeat the step until there is one row left. If that last row is not clear by luck, my intuition is that it's the "impossible" case.
#include <memory>
template <typename Elem>
class Arr_2d
{
public:
Arr_2d(unsigned r, unsigned c)
: rows_(r), columns_(c), data(new Elem[rows_ * columns_]) { }
Elem * operator [] (unsigned row_idx)
{ return(data.get() + (row_idx * columns_)); }
unsigned rows() const { return(rows_); }
unsigned columns() const { return(columns_); }
private:
const unsigned rows_, columns_;
std::unique_ptr<Elem []> data;
};
inline void toggle_one(bool &b) { b = !b; }
void toggle(Arr_2d<bool> &tab, unsigned row, unsigned column)
{
toggle_one(tab[row][column]);
if (column > 0)
toggle_one(tab[row][column - 1]);
if (row > 0)
toggle_one(tab[row - 1][column]);
if (column < (tab.columns() - 1))
toggle_one(tab[row][column + 1]);
if (row < (tab.rows() - 1))
toggle_one(tab[row + 1][column]);
}
int solve(Arr_2d<bool> &tab)
{
int count = 0;
unsigned i = 0;
for ( ; i < (tab.rows() - 1); ++i)
for (unsigned j = 0; j < tab.columns(); ++j)
if (tab[i][j])
{
toggle(tab, i + 1, j);
++count;
}
for (unsigned j = 0; j < tab.columns(); ++j)
if (tab[i][j])
// Impossible.
return(-count);
return(count);
}
unsigned ex1[] = {
0, 1, 0,
1, 1, 1,
0, 1, 0
};
unsigned ex2[] = {
0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 1, 0, 1, 0, 1, 0,
0, 0, 1, 1, 0, 1, 1, 1,
1, 1, 0, 1, 1, 1, 0, 0,
1, 0, 1, 1, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 0
};
Arr_2d<bool> load(unsigned rows, unsigned columns, const unsigned *data)
{
Arr_2d<bool> res(rows, columns);
for (unsigned i = 0; i < rows; ++i)
for (unsigned j = 0; j < columns; ++j)
res[i][j] = !!*(data++);
return(res);
}
#include <iostream>
int main()
{
{
Arr_2d<bool> tab = load(3, 3, ex1);
std::cout << solve(tab) << '\n';
}
{
Arr_2d<bool> tab = load(6, 8, ex2);
std::cout << solve(tab) << '\n';
}
return(0);
}
The problem is stated like this:
y
yxy If you flip x, then you have to flip all the ys
y
But it's easy if you think about it like this:
x
yyy If you flip x, then you have to flip all the ys
y
It's the same thing, but now the solution is obvious -- You must flip all the 1s in row 0, which will flip some bits in rows 1 and 2, then you must flip all the 1s in row 1, etc, until you get to the end.
If this is indeed the Lights Out game, then there are plenty of resources that detail how to solve the game. It is also quite likely that this is a duplicate of Lights out game algorithm, as has already been mentioned by other posters.
Let's see if we can't solve the first sample puzzle provided, however, and at least present a concrete description of an algorithm.
The initial puzzle appears to be solvable:
1 0 1
1 1 1
0 1 0
The trick is that you can clear 1's in the top row by changing the values in the row underneath them. I'll provide coordinates by row and column, using a 1-based offset, meaning that the top left value is (1, 1) and the bottom right value is (3, 3).
Change (2, 1), then (2, 3), then (3, 2). I'll show the intermediate states of the board with the * for the cell being changed in the next step.
1 0 1 (2,1) 0 0 1 (2,3) 0 0 0 (3, 2) 0 0 0
* 1 1 ------> 0 0 * ------> 0 1 0 ------> 0 0 0
0 1 0 1 1 0 1 * 1 0 0 0
This board can be solved, and the number of moves appears to be 3.
The pseudo-algorithm is as follows:
flipCount = 0
for each row _below_ the top row:
for each element in the current row:
if the element in the row above is 1, toggle the element in this row:
increment flipCount
if the board is clear, output flipCount
if the board isnt clear, output "Impossible"
I hope this helps; I can elaborate further if required but this is the core of the standard lights out solution. BTW, it is related to Gaussian Elimination; linear algebra crops up in some odd situations :)
Finally, in terms of what is wrong with your code, it appears to be the following loop:
for(int i=0; i<n-1; i++)
{
for(int j=0; j<m-1; j++)
{
if(tab[i][j] == 1 && i > 0 && j > 0)
{
tab[i-1][j] = !tab[i-1][j];
tab[i+1][j] = !tab[i+1][j];
tab[i][j+1] = !tab[i][j+1];
tab[i][j-1] = !tab[i][j-1];
tab[i][j] = !tab[i][j];
counter ++;
}
}
}
Several issues occur to me, but first assumptions again:
i refers to the ith row and there are n rows
j refers to the jth column and there are m columns
I'm now referring to indices that start from 0 instead of 1
If this is the case, then the following is observed:
You could run your for i loop from 1 instead of 0, which means you no longer have to check whether i > 0 in the if statement
You should drop the for j > 0 in the if statement; that check means that you can't flip anything in the first column
You need to change the n-1 in the for i loop as you need to run this for the final row
You need to change the m-1 in the for j loop as you need to run this for the final column (see point 2 also)
You need to check the cell in the row above the current row, so you you should be checking tab[i-1][j] == 1
Now you need to add bounds tests for j-1, j+1 and i+1 to avoid reading outside valid ranges of the matrix
Put these together and you have:
for(int i=1; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(tab[i-1][j] == 1)
{
tab[i-1][j] = !tab[i-1][j];
if (i+1 < n)
tab[i+1][j] = !tab[i+1][j];
if (j+1 < m)
tab[i][j+1] = !tab[i][j+1];
if (j > 0)
tab[i][j-1] = !tab[i][j-1];
tab[i][j] = !tab[i][j];
counter ++;
}
}
}
A little class that can take as a input file or test all possible combination for first row with only zeros, on 6,5 matrix:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
typedef std::vector< std::vector<int> > Matrix;
class MatrixCleaner
{
public:
void swapElement(int row, int col)
{
if (row >= 0 && row < (int)matrix.size() && col >= 0 && col < (int)matrix[row].size())
matrix[row][col] = !matrix[row][col];
}
void swapElements(int row, int col)
{
swapElement(row - 1, col);
swapElement(row, col - 1);
swapElement(row, col);
swapElement(row, col + 1);
swapElement(row + 1, col);
}
void printMatrix()
{
for (auto &v : matrix)
{
for (auto &val : v)
{
std::cout << val << " ";
}
std::cout << "\n";
}
}
void loadMatrix(std::string path)
{
std::ifstream fileStream;
fileStream.open(path);
matrix.resize(1);
bool enconteredNumber = false;
bool skipLine = false;
bool skipBlock = false;
for (char c; fileStream.get(c);)
{
if (skipLine)
{
if (c != '*')
skipBlock = true;
if (c != '\n')
continue;
else
skipLine = false;
}
if (skipBlock)
{
if (c == '*')
skipBlock = false;
continue;
}
switch (c)
{
case '0':
matrix.back().push_back(0);
enconteredNumber = true;
break;
case '1':
matrix.back().push_back(1);
enconteredNumber = true;
break;
case '\n':
if (enconteredNumber)
{
matrix.resize(matrix.size() + 1);
enconteredNumber = false;
}
break;
case '#':
if(!skipBlock)
skipLine = true;
break;
case '*':
skipBlock = true;
break;
default:
break;
}
}
while (matrix.size() > 0 && matrix.back().empty())
matrix.pop_back();
fileStream.close();
}
void loadRandomValidMatrix(int seed = -1)
{
//Default matrix
matrix = {
{ 0,0,0,0,0 },
{ 0,0,0,0,0 },
{ 0,0,0,0,0 },
{ 0,0,0,0,0 },
{ 0,0,0,0,0 },
{ 0,0,0,0,0 },
};
int setNum = seed;
if(seed < 0)
if(seed < -1)
setNum = std::rand() % -seed;
else
setNum = std::rand() % 33554432;
for (size_t r = 1; r < matrix.size(); r++)
for (size_t c = 0; c < matrix[r].size(); c++)
{
if (setNum & 1)
swapElements(r, c);
setNum >>= 1;
}
}
bool test()
{
bool retVal = true;
for (int i = 0; i < 33554432; i++)
{
loadRandomValidMatrix(i);
if( (i % 1000000) == 0 )
std::cout << "i= " << i << "\n";
if (clean() < 0)
{
// std::cout << "x";
std::cout << "\n" << i << "\n";
retVal = false;
break;
}
else
{
// std::cout << ".";
}
}
return retVal;
}
int clean()
{
int numOfSwaps = 0;
try
{
for (size_t r = 1; r < matrix.size(); r++)
{
for (size_t c = 0; c < matrix[r].size(); c++)
{
if (matrix.at(r - 1).at(c))
{
swapElements(r, c);
numOfSwaps++;
}
}
}
}
catch (...)
{
return -2;
}
if (!matrix.empty())
for (auto &val : matrix.back())
{
if (val == 1)
{
numOfSwaps = -1;
break;
}
}
return numOfSwaps;
}
Matrix matrix;
};
int main(int argc, char **argv)
{
std::srand(std::time(NULL));
MatrixCleaner matrixSwaper;
if (argc > 1)
{
matrixSwaper.loadMatrix(argv[argc - 1]);
std::cout << "intput:\n";
matrixSwaper.printMatrix();
int numOfSwaps = matrixSwaper.clean();
std::cout << "\noutput:\n";
matrixSwaper.printMatrix();
if (numOfSwaps > 0)
std::cout << "\nresult = " << numOfSwaps << " matrix is clean now " << std::endl;
else if (numOfSwaps == 0)
std::cout << "\nresult = " << numOfSwaps << " nothing to clean " << std::endl;
else
std::cout << "\nresult = " << numOfSwaps << " matrix cannot be clean " << std::endl;
}
else
{
std::cout << "Testing ";
if (matrixSwaper.test())
std::cout << " PASS\n";
else
std::cout << " FAIL\n";
}
std::cin.ignore();
return 0;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
For example, the first row should be filled with all 1. In the second row, every second element should be filled with 1 and other elements with 0. In the third row, every third element should be filled with 1 and others with 0, and so on.
1, 1, 1, 1, 1, ...
1, 0, 1, 0, 1, ...
1, 0, 0, 1, 0, ...
1, 0, 0, 0, 1, ...
As usual there are many ways to do the task. For example you can use the following solution
#include <iostream>
int main()
{
const size_t M = 5;
const size_t N = 10;
int a[M][N];
for ( size_t i = 0; i < M; i++ )
{
for ( size_t j = 0; j < N; j++ ) a[i][j] = ( j + 1 ) % ( i + 1 ) == 0;
}
for ( const auto &row : a )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The program output is
1 1 1 1 1 1 1 1 1 1
0 1 0 1 0 1 0 1 0 1
0 0 1 0 0 1 0 0 1 0
0 0 0 1 0 0 0 1 0 0
0 0 0 0 1 0 0 0 0 1
If your compiler does not support the range-based for loop
for ( const auto &row : a )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
then you can substitute it for an ordinary loop. For example
for ( size_t i = 0; i < M; i++ )
{
for ( size_t j = 0; j < N; j++ ) std::cout << a[i][j] << ' ';
std::cout << std::endl;
}