The problem statement you can read from this: https://practice.geeksforgeeks.org/problems/find-whether-path-exist/0
Following is the C++ code in the last. I am getting different output by just commenting the cout statements when I run it on the following input (3: walkable path, 1: source, 2: destination, 0: wall):
1
8
3 3 3 3 0 0 3 0
1 3 3 3 3 3 3 2
3 3 0 3 0 3 3 3
3 3 3 0 0 3 3 0
0 3 3 3 3 3 3 3
0 0 0 3 3 0 3 3
0 3 0 3 3 3 3 0
3 3 3 0 3 3 3 3
On the Line no 31st and 35th, there are cout<<"found: 1\n"; and cout<<"found: 2\n"; printing statements that I was using to debug the code. The statements are printing pure quoted strings (doesn't uses/includes any variable). I came to know that if I don't comment at least one of the line (let say only 31st line), the output is like:
found: 1
1
And if I comment both of the lines I am getting output:
0
I am not able to understand this behavior of the program. The correct ans is 1 as there is a path between 1 and 2 in the matrix. But I don't want to print the lines I have mentioned that was only for debugging. So on commenting them I am getting wrong answer 0. So can anyone find the fault/reason for such behavior? Following is the entire code that you can copy and paste into your editor:
// { Driver Code Starts
#include<bits/stdc++.h>
using namespace std;
// } Driver Code Ends
class Solution {
public:
// int n = 0;
// void printTab(int n) {
// while(n-- > 0) cout<<" ";
// }
void DFS(int i, int j, bool *found1, bool *found2,
unordered_set<string> visited, vector<vector<int>>& grid) {
// printTab(++n);
// cout<<">> "<<i<<", "<<j<<"\n";
// n--;
visited.insert(i+"_"+j);
if(grid[i][j] == 0) return;
else if(grid[i][j] == 1) {
*found1 = true;
cout<<"found: 1\n";
}
else if(grid[i][j] == 2) {
*found2 = true;
// cout<<"found: 2\n";
}
// switch(grid[i][j]) {
// case 0: return;
// case 1: *found1 = true;cout<<"found: 1\n";break;
// case 2: *found2 = true;break;
// }
if(*found1 && *found2)
return;
int r, c;
// Down
r = i+1;
c = j;
if((r>=0 && r<grid.size() && c>=0 && c<grid[0].size() && !visited.count(r+"_"+c)))
DFS(r, c, found1, found2, visited, grid);
if(*found1 && *found2)
return;
// Left
r = i;
c = j-1;
if((r>=0 && r<grid.size() && c>=0 && c<grid[0].size() && !visited.count(r+"_"+c)))
DFS(r, c, found1, found2, visited, grid);
if(*found1 && *found2)
return;
// Right
r = i;
c = j+1;
if((r>=0 && r<grid.size() && c>=0 && c<grid[0].size() && !visited.count(r+"_"+c)))
DFS(r, c, found1, found2, visited, grid);
if(*found1 && *found2)
return;
// Up
r = i-1;
c = j;
if((r>=0 && r<grid.size() && c>=0 && c<grid[0].size() && !visited.count(r+"_"+c)))
DFS(r, c, found1, found2, visited, grid);
}
bool is_Possible(vector<vector<int>>& grid) {
bool found1, found2;
found1 = found2 = false;
unordered_set<string> visited;
for(int i=0; i<grid.size(); i++) {
for(int j=0; j<grid[0].size(); j++) {
if(!visited.count(i+"_"+j)) {
DFS(i, j, &found1, &found2, visited, grid);
if(found1 || found2)
return (found1 && found2);
}
}
}
return false;
}
};
// { Driver Code Starts.
int main(){
int tc;
cin >> tc;
while(tc--){
int n;
cin >> n;
vector<vector<int>>grid(n, vector<int>(n, -1));
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
cin >> grid[i][j];
}
}
Solution obj;
bool ans = obj.is_Possible(grid);
cout << ((ans) ? "1\n" : "0\n");
}
return 0;
} // } Driver Code Ends
This is undefined behaviour
if(!visited.count(i+"_"+j)) {
Clearly you think you are forming a string such as "1_2" but actually you are doing pointer arithmetic by adding an integer to a char* pointer.
Try this instead
if(!visited.count(std::to_string(i)+"_"+std::to_string(j))) {
Initially my algorithm involved testing every number from 1->n of an nxn sudoku but since it couldn't solve 16x16 sudokus (had the algorithm running for 3 hours with no luck) I thought it would be better to choose numbers in a cell based on the most valid and least used number on the board. I think I've figured out most of it, e.g. I made a 2D vector called usage (first column is number and second is usage) which I sort every time I make a change on the board. Right now I can solve an easy 9x9 and an empty 16x16 but I'm having no luck elsewhere. Wondering if somebody could help me spot where my logic is lacking.
//I used stack <pair<int, int>> to store the most recent row and column we've placed a value in. The first int is the row and the second is the column.
#include <stack>
#include <vector>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
bool isRowValid(vector <vector <int>> &sudoku, int row, int possval);
bool isColumnValid(vector <vector <int>> &sudoku, int column, int possval);
int assignBlock9x9(int pos);
int assignBlock16x16(int pos);
int assignBlock25x25(int pos);
bool isBlockValid(vector <vector <int>> &sudoku, int row, int column, int possval);
bool isValidSingle(vector <vector <int>> &sudoku, int row, int column, int possval);
bool isRowValid2(vector <vector <int>> &sudoku, int row, int possval);
bool isColumnValid2(vector <vector <int>>& sudoku, int column, int possval);
bool isBlockValid2(vector <vector <int>>& sudoku, int row, int column, int possval);
bool isValidSingle2(vector <vector <int>>& sudoku, int row, int column, int possval);
int solve(vector <vector <int>>& sudoku);
vector <vector<int>> Usage(vector <vector <int>>& sudoku);
bool sortcol(const vector<int>& v1, const vector<int>& v2);
bool sortcol2(const vector<int>& v1, const vector<int>& v2);
void printSudoku(vector <vector <int>>& sudokusudoku);
void printUsage(vector<vector<int>>& usage);
/* easy sudoku (9x9_1.txt) - actually solves
0 4 0 0 0 0 1 7 9
0 0 2 0 0 8 0 5 4
0 0 6 0 0 5 0 0 8
0 8 0 0 7 0 9 1 0
0 5 0 0 9 0 0 3 0
0 1 9 0 6 0 0 4 0
3 0 0 4 0 0 7 0 0
5 7 0 1 0 0 2 0 0
9 2 8 0 0 0 0 6 0*/
/*solution
8 4 5 6 3 2 1 7 9
7 3 2 9 1 8 6 5 4
1 9 6 7 4 5 3 2 8
6 8 3 5 7 4 9 1 2
4 5 7 2 9 1 8 3 6
2 1 9 8 6 3 5 4 7
3 6 1 4 2 9 7 8 5
5 7 4 1 8 6 2 9 3
9 2 8 3 5 7 4 6 1*/
/*medium sudoku (9x9_2.txt) - can't solve
0 9 0 3 8 4 0 0 0
0 0 2 0 7 0 0 0 0
0 0 0 0 0 0 0 7 1
5 0 0 0 0 3 2 4 0
0 3 0 0 0 0 0 0 0
0 0 1 0 0 5 0 9 0
0 0 0 8 0 0 0 0 0
7 0 6 5 2 0 0 0 0
0 0 0 0 0 6 4 0 0*/
/*solution
1 9 7 3 8 4 5 6 2
8 5 2 6 7 1 9 3 4
4 6 3 9 5 2 8 7 1
5 8 9 7 1 3 2 4 6
6 3 4 2 9 8 7 1 5
2 7 1 4 6 5 3 9 8
3 1 5 8 4 7 6 2 9
7 4 6 5 2 9 1 8 3
9 2 8 1 3 6 4 5 7*/
/* hard sudoku (9x9_3.txt) - can't solve
7 9 0 0 0 0 0 0 3
0 0 0 0 0 0 0 6 0
8 0 1 0 0 4 0 0 2
0 0 5 0 0 0 0 0 0
3 0 0 1 0 0 0 0 0
0 4 0 0 0 6 2 0 9
2 0 0 0 3 0 0 0 6
0 3 0 6 0 5 4 2 1
0 0 0 0 0 0 0 0 0*/
/*solution
7 9 2 5 6 8 1 4 3
4 5 3 2 1 9 8 6 7
8 6 1 3 7 4 9 5 2
6 2 5 8 9 3 7 1 4
3 7 9 1 4 2 6 8 5
1 4 8 7 5 6 2 3 9
2 8 4 9 3 1 5 7 6
9 3 7 6 8 5 4 2 1
5 1 6 4 2 7 3 9 8*/
/* no solution sudoku (9x9_4.txt) - can't solve
0 0 0 0 0 0 0 0 7
7 2 0 3 0 9 0 0 1
0 0 8 7 0 5 0 6 0
5 0 2 8 9 0 0 0 0
0 4 0 5 0 1 0 9 0
0 0 0 0 6 3 7 0 5
0 3 0 9 0 6 1 7 0
2 0 0 1 0 7 0 5 3
9 0 0 0 0 0 0 0 0
*/
int main()
{
fstream MySudoku("9x9_1.txt");
vector <vector <int>> sudoku;
//input from text file
if (MySudoku.is_open()) {
string row;
while (getline(MySudoku, row)) {
stringstream rowelement (row);
string num;
vector <int> row;
while (getline(rowelement, num, ' ')) {
if ((int)num[0] >= 65) {
row.push_back((int)num[0] - 55);
}
else {
row.push_back((int)num[0] - 48);
}
}
sudoku.push_back(row);
rowelement.clear();
//cout << row;
//cout << endl;
}
MySudoku.close();
}
//input from testing bot
/*string row;
int i = 0;
int rowsize = 9;
while (i < rowsize) {
getline(cin, row);
stringstream rowelement(row);
string num;
vector <int> row;
rowsize = 0;
while (getline(rowelement, num, ' ')) {
if ((int)num[0] >= 65) {
row.push_back((int)num[0] - 55);
}
else {
row.push_back((int)num[0] - 48);
//cout << 500 + (int)num[0] - 48;
}
++rowsize;
}
//cout << rowsize;
sudoku.push_back(row);
rowelement.clear();
++i;
}
*/
//solving and printing out the resulting sudoku if possible
int solved = solve(sudoku);
if (solved == 1) {
printSudoku(sudoku);
}
else {
cout << "No Solution";
}
}
void printSudoku(vector <vector <int>>& sudoku) {
for (unsigned int i = 0; i < sudoku.size(); i++) {
for (unsigned int j = 0; j < sudoku.size(); j++) {
if (sudoku[i][j] >= 10) {
if (j == sudoku.size() - 1) {
cout << (char)(sudoku[i][j] + 55);
}
else {
cout << (char)(sudoku[i][j] + 55) << " ";
}
}
else {
if (j == sudoku.size() - 1) {
cout << sudoku[i][j];
}
else {
cout << sudoku[i][j] << " ";
}
}
}
cout << endl;
}
}
void printUsage(vector<vector<int>> &usage) {
for (vector <int> usagerow : usage) {
cout << usagerow[0] << " : " << usagerow[1] << " ";
}
cout << endl << endl;
}
int solve(vector <vector <int>>& sudoku) {
stack <pair<int, int>> solution;
vector <vector <int>> usage = Usage(sudoku);
//printUsage(usage);
///////////initializes solution
int breaker = 0;
//pushes value on empty cell
for (unsigned int row = 0; row < sudoku.size(); row++) {
if (breaker == 2002) {
break;
}
for (unsigned int column = 0; column < sudoku.size(); column++) {
if (breaker == 2002) {
break;
}
if (sudoku[row][column] == 0) {
//choose option based on usage and then change usage list
int vectorpos = 0;
while (!isValidSingle(sudoku, row, column, usage[vectorpos][0]) && vectorpos != sudoku.size() - 1) {
++vectorpos;
}
//cout << usage[vectorpos][0] << " was pushed at " << row << column << endl;
sudoku[row][column] = usage[vectorpos][0];
usage[vectorpos][1] = usage[vectorpos][1] + 1;
sort(usage.begin(), usage.begin() + usage.size(), sortcol);
sort(usage.begin(), usage.begin() + usage.size(), sortcol2);
solution.push(make_pair(row, column));
breaker = 2002;
break;
}
}
}
//printSudoku(sudoku);
//just prints out the usage vector {not useful}
//printUsage(usage);
/////actual solution
bool solved = false;
while (!solved) {
//cout << "top of stack is " << solution.top().first << solution.top().second << endl;
int lastrow = solution.top().first;
int lastcolumn = solution.top().second;
//checks if sudoku is in invalid state
if (!isValidSingle2(sudoku, lastrow, lastcolumn, sudoku[lastrow][lastcolumn])) {
//copy of usage vector to allow us to see if we're at the last option for the cell
vector <vector <int>> usagefuture = usage;
for (vector<int> &usagerowdec : usagefuture) {
if (sudoku[solution.top().first][solution.top().second] == usagerowdec[0]) {
usagerowdec[1] = usagerowdec[1] - 1;
sort(usagefuture.begin(), usagefuture.begin() + usagefuture.size(), sortcol);
sort(usagefuture.begin(), usagefuture.begin() + usagefuture.size(), sortcol2);
break;
}
}
//cout << "future -> "; printUsage(usagefuture);
//keeps popping last decision until sudoku no longer in invalid state
while (sudoku[solution.top().first][solution.top().second] == usagefuture[sudoku.size()-1][0]) {
//looks for where the last entered value occurs in the usage vector
int val = sudoku[solution.top().first][solution.top().second];
for (vector <int> usagerowdec : usage) {
if (usagerowdec[0]==val) {
//sets cell to 0 and pops
sudoku[solution.top().first][solution.top().second] = 0;
//cout << usagerowdec[0] << " was set back to 0" /*<< solution.top().first << solution.top().first*/ << endl;
solution.pop();
//cout << "top of stack is now " << solution.top().first << solution.top().second << endl;
//permanently changes the usage vector
usage = usagefuture;
sort(usage.begin(), usage.begin() + usage.size(), sortcol);
sort(usage.begin(), usage.begin() + usage.size(), sortcol2);
break;
}
}
if (solution.size() == 0) {
return 0;
}
//copy of usage vector to allow us to see if we're at the last option for the cell
usagefuture = usage;
for (vector<int>& usagerowdec : usagefuture) {
if (sudoku[solution.top().first][solution.top().second] == usagerowdec[0]) {
usagerowdec[1] = usagerowdec[1] - 1;
sort(usagefuture.begin(), usagefuture.begin() + usagefuture.size(), sortcol);
sort(usagefuture.begin(), usagefuture.begin() + usagefuture.size(), sortcol2);
break;
}
}
//cout << "future -> "; printUsage(usagefuture);
}
if (solution.size() == 0) {
return 0;
}
else {
int row = solution.top().first;
int column = solution.top().second;
//printUsage(usage);
//decrements usage vector at value we're changing
for (vector<int>& usagerowdec : usage) {
if (sudoku[row][column] == usagerowdec[0]) {
usagerowdec[1] = usagerowdec[1] - 1;
sort(usage.begin(), usage.begin() + usage.size(), sortcol);
sort(usage.begin(), usage.begin() + usage.size(), sortcol2);
break;
}
}
//printSudoku(sudoku);
//finds which value we're on in the usage vector
int vectorpos = 0;
for (int i = 0; i < usage.size(); i++) {
if (sudoku[row][column] == usage[i][0]) {
vectorpos = i;
break;
}
}
//sees what next value we can set it to. If nothing it becomes the last possible value
while (!isValidSingle(sudoku, row, column, usage[vectorpos][0]) && vectorpos != sudoku.size() - 1) {
vectorpos++;
}
//cout << "vectorpos is " << vectorpos << ": ";
//completes the change
//cout << sudoku[row][column] << " was changed to " << usage[vectorpos][0] << " at " << row << column << endl;
sudoku[row][column] = usage[vectorpos][0];
usage[vectorpos][1] = usage[vectorpos][1] + 1;
sort(usage.begin(), usage.begin() + usage.size(), sortcol);
sort(usage.begin(), usage.begin() + usage.size(), sortcol2);
}
}
//if sudoku in valid state
else {
int breaker = 0;
//looks for empty cell to push to
for (unsigned int row = 0; row < sudoku.size(); row++) {
if (breaker == 2002) {
break;
}
for (unsigned int column = 0; column < sudoku.size(); column++) {
if (breaker == 2002) {
break;
}
if (sudoku[row][column] == 0) {
//choose option based on usage and then change usage list, worst case is the last value like with the change
int vectorpos = 0;
while (!isValidSingle(sudoku, row, column, usage[vectorpos][0]) && vectorpos != sudoku.size() - 1) {
++vectorpos;
}
//cout << usage[vectorpos][0] << " was pushed at " << row << column << endl;
sudoku[row][column] = usage[vectorpos][0];
usage[vectorpos][1] = usage[vectorpos][1] + 1;
sort(usage.begin(), usage.begin() + usage.size(), sortcol);
sort(usage.begin(), usage.begin() + usage.size(), sortcol2);
solution.push(make_pair(row, column));
breaker = 2002;
break;
}
}
}
}
//checks if we're at the end
if (solution.top().first == sudoku.size() - 1 && solution.top().second == sudoku.size() - 1){
solved = true;
}
//printSudoku(sudoku);
//prints out usage vector {not useful}
//printUsage(usage);
}
return 1;
}
bool isRowValid(vector <vector <int>> &sudoku, int row, int possval) {
for (unsigned int i = 0; i < sudoku.size(); i++) {
if (possval == sudoku[row][i]) {
return false;
}
}
return true;
}
bool isColumnValid(vector <vector <int>> &sudoku, int column, int possval) {
for (unsigned int j = 0; j < sudoku.size(); j++) {
if (possval == sudoku[j][column]) {
return false;
}
}
return true;
}
int assignBlock9x9(int pos) {
if (0 <= pos && pos <= 2) {
return 0;
}
else if (3 <= pos && pos <= 5) {
return 3;
}
else {
return 6;
}
}
int assignBlock16x16(int pos) {
if (0 <= pos && pos <= 3) {
return 0;
}
else if (4 <= pos && pos <= 7) {
return 4;
}
else if (8 <= pos && pos <= 11){
return 8;
}
else {
return 12;
}
}
int assignBlock25x25(int pos) {
if (0 <= pos && pos <= 4) {
return 0;
}
else if (5 <= pos && pos <= 9) {
return 5;
}
else if(10 <= pos && pos <= 14){
return 10;
}
else if (15 <= pos && pos <= 19) {
return 15;
}
else {
return 20;
}
}
bool isBlockValid(vector <vector <int>> &sudoku, int row, int column, int possval) {
//if 9x9
if (sudoku.size() == 9) {
int startrow = assignBlock9x9(row);
int startcolumn = assignBlock9x9(column);
for (int i = startrow; i <= startrow + 2; i++) {
for (int j = startcolumn; j <= startcolumn + 2; j++) {
if (possval == sudoku[i][j]) {
return false;
}
}
}
}
//if 16x16
else if (sudoku.size()==16) {
int startrow = assignBlock16x16(row);
int startcolumn = assignBlock16x16(column);
for (int i = startrow; i <= startrow + 3; i++) {
for (int j = startcolumn; j <= startcolumn + 3; j++) {
if (possval == sudoku[i][j]) {
return false;
}
}
}
}
//if 25x25
else {
int startrow = assignBlock25x25(row);
int startcolumn = assignBlock25x25(column);
for (int i = startrow; i <= startrow + 4; i++) {
for (int j = startcolumn; j <= startcolumn + 4; j++) {
if (possval == sudoku[i][j]) {
return false;
}
}
}
}
return true;
}
bool isValidSingle(vector <vector <int>> &sudoku, int row, int column, int possval) {
if (isRowValid(sudoku, row, possval) && isColumnValid(sudoku, column, possval) && isBlockValid(sudoku, row, column, possval)) {
return true;
}
return false;
}
bool isRowValid2(vector <vector <int>> &sudoku, int row, int possval) {
int samecount = 0;
for (unsigned int i = 0; i < sudoku.size(); i++) {
if (sudoku[row][i] == possval) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
return true;
}
bool isColumnValid2(vector <vector <int>> &sudoku, int column, int possval) {
int samecount = 0;
for (unsigned int j = 0; j < sudoku.size(); j++) {
if (sudoku[j][column] == possval) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
return true;
}
bool isBlockValid2(vector <vector <int>>& sudoku, int row, int column, int possval) {
int samecount = 0;
//if 9x9
if (sudoku.size() == 9) {
int startrow = assignBlock9x9(row);
int startcolumn = assignBlock9x9(column);
for (int i = startrow; i <= startrow + 2; i++) {
for (int j = startcolumn; j <= startcolumn + 2; j++) {
if (possval == sudoku[i][j]) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
}
}
//if 16x16
else if (sudoku.size() == 16) {
int startrow = assignBlock16x16(row);
int startcolumn = assignBlock16x16(column);
for (int i = startrow; i <= startrow + 3; i++) {
for (int j = startcolumn; j <= startcolumn + 3; j++) {
if (possval == sudoku[i][j]) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
}
}
//if 25x25
else {
int startrow = assignBlock25x25(row);
int startcolumn = assignBlock25x25(column);
for (int i = startrow; i <= startrow + 4; i++) {
for (int j = startcolumn; j <= startcolumn + 4; j++) {
if (possval == sudoku[i][j]) {
++samecount;
}
if (samecount == 2) {
return false;
}
}
}
}
return true;
}
bool isValidSingle2(vector <vector <int>> &sudoku, int row, int column, int possval) {
if (isRowValid2(sudoku, row, possval) && isColumnValid2(sudoku, column, possval) && isBlockValid2(sudoku, row, column, possval)) {
return true;
}
return false;
}
bool sortcol(const vector<int>& v1, const vector<int>& v2) {
return v1[1] < v2[1];
}
bool sortcol2(const vector<int>& v1, const vector<int>& v2) {
return v1[0] < v2[0] && v1[1] == v2[1];
}
vector <vector <int>> Usage(vector <vector <int>> &sudoku) {
vector <int> usage;
vector <vector <int>> usage2;
for (unsigned int i = 0; i < sudoku.size(); i++) {
usage.push_back(0);
}
for (unsigned int row = 0; row < sudoku.size(); row++) {
for (unsigned int column = 0; column < sudoku.size(); column++) {
if (sudoku[row][column] == 0) {
continue;
}
usage[sudoku[row][column] -1] = usage[sudoku[row][column] - 1] + 1;
}
}
for (unsigned int i = 1; i <= sudoku.size(); i++) {
usage2.push_back({(int) i, usage[i - 1] });
}
sort(usage2.begin(), usage2.begin() + usage2.size(), sortcol);
sort(usage2.begin(), usage2.begin() + usage2.size(), sortcol2);
return usage2;
}
In this problem, we will say that a permutation is cool is it does not have two adjacent consecutive numbers. Given n, print all the cool permutations of {0, …, n − 1}.
Input
input consists of several cases, each with an n between 1 and 9.
Output
For every case, print in lexicographical order all the cool permutations of {0, …, n − 1}.
I know how to solve the problem that prints all the permutations of { 1, …, n-1 } in lexicographical order. But I do not know how to generate the permutations without two adjacent consecutive numbers.
#include <iostream>
#include <vector>
using namespace std;
void write(const vector<int>& v) {
int s = v.size()-1;
for (int i = 0; i < s; ++i) cout << v[i] << ' ';
cout << v[s] << endl;
}
void generate(vector<int>& v, vector<bool>& u, int i, int n) {
if (i == n) write(v);
else {
for (int s = 1; s <= n; ++s) {
if (not u[s]) {
v[i] = s;
u[s] = true;
generate(v, u, i+1, n);
u[s] = false;
}
}
}
}
int main() {
int n;
while (cin >> n) {
vector<int> v(n);
vector<bool> u(n, false);
generate(v, u, 0, n-1);
cout << endl;
}
}
With this input:
1
2
3
4
5
I expect this output:
0
1 3 0 2
2 0 3 1
0 2 4 1 3
0 3 1 4 2
1 3 0 2 4
1 3 0 4 2
1 4 2 0 3
2 0 3 1 4
2 0 4 1 3
2 4 0 3 1
2 4 1 3 0
3 0 2 4 1
3 1 4 0 2
3 1 4 2 0
4 1 3 0 2
4 2 0 3 1
Thanks in advance!
An inefficient way of generating cool permutations, would be to first generate all permutations, and then to create a method that takes the vector v (who stores a candidate permutation), and evaluate whether this permutation is cool or not. If yes, print, if no, skip it, as #YSC suggested.
Example:
bool isCool(const vector<int>& v)
{
// special case, v.size==2
if(v.size() == 2) {
if(v[0] == v[1] + 1 || v[0] == v[1] - 1) {
return false;
} else {
return true;
}
}
// start from second element to pre-last
// and check if prev and next are adjacent to it
for(size_t i = 1; i < v.size() - 1; ++i) {
if(v[i] == v[i - 1] + 1 || v[i] == v[i - 1] - 1 ||
v[i] == v[i + 1] + 1 || v[i] == v[i + 1] - 1)
return false;
}
return true;
}
and then you would use it like in your generate method:
if (i == n && isCool(v)) write(v);
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
using namespace std;
bool ConsecValues(int x, int y)
{
return abs(x - y) == 1;
}
bool HasConsecAdjValues(const vector<int>& v)
{
vector<int>::const_iterator cIter = adjacent_find(v.cbegin(), v.cend(),
ConsecValues);
return cIter != v.end();
}
vector<vector<int>> GetCoolPerms(int n)
{
vector<vector<int>> result;
vector<int> v(n);
iota(v.begin(), v.end(), 0);
do {
if (!HasConsecAdjValues(v))
result.push_back(v);
} while (std::next_permutation(v.begin(), v.end()));
return result;
}
void PrintPerm(const vector<int>& v)
{
for (const auto& num : v)
cout << num;
cout << endl;
}
int main()
{
vector<vector<int>> coolPerms = GetCoolPerms(5);
for (const auto& perm : coolPerms)
PrintPerm(perm);
getchar();
}
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;
}
I'm trying to write a program that creates a matrix of size N, and puts numbers in so that no numbers repeat in the same column/row using backtracking.
1) Put value in cell. If it's a repeat, try a different value.
2) If no such value exists, backtrack 1 cell, and change the value. //recursive
However, the highest number repeats a few times sometimes. E.g:
3 1 2 3 1 2 4 5 2 4 1 3 6 5
1 3 3 2 3 1 5 4 4 3 2 5 1 6
2 3 1 1 2 5 3 5 < 1 5 3 2 4 6
4 5 3 1 2 5 1 6 4 2 3
5 4 5 2 1 < 6 2 4 1 3 6 <
^ 3 6 5 6 6 4 <
^
And here's what it's doing:
Once it runs out of numbers to put into a cell (i.e: all restricted, it puts N in)
3 1 2 4 3 1 2 4 3 1 2 4 3 1 2 4
1 2 3 0 -> 1 2 3 3 -> 1 2 3 4 -> 1 2 3 4
0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
I'm really stuck here, hopefully someone can find the error in my code:
int **grid; //2d dynamic array of size 'size'
bool checkRepeat(size,**grid,row,column); //checks if a number in a column/row is a repeat
int backtrack = 0;
int holder = 0; //when backtracking, this holds the number that should be changed
bool checkRepeat(int x, int** grid, int row, int col){
for (int i = 0; i < x; i++){
if (grid[row][col] == grid[row][i] && col != i){
return true;
}
}
for (int j = 0; j < x; j++){
if (grid[row][col] == grid[j][col] && row != j){
return true;
}
}
return false;
}
int main(){
for (int row = 0; row < size; row++){
for (int col = 0; col < size; col++){
if (backtrack == 0){
grid[row][col] = rand() % size + 1;
}
if (backtrack == 1){ //If backtracking, go back one cell.
grid[row][col] = 0; //(Since the above for loops went one
if (col == 0){ //cell forward, go 2 cells back)
col = size - 2;
row--;
} else if (col == 1){
col = size - 1;
row--;
} else {
col-=2;
}
holder = grid[row][col]; //put the current number into holder to avoid it
backtrack = 0;
}
/*the following checks if the number in the current cell is
a repeat and makes sure the number isn't the same as
before (holder). Then it checks all possible numbers (1 to size)
and puts one that matches the rules. If one is not found,
program backtracks 1 cell*/
if (checkRepeat(size,grid,row,col) && grid[row][col] > 0){
for (int x = 1; x < size+1 && (checkRepeat(x,grid,row,col) || holder == grid[row][col]); x++){
grid[row][col] = x;
}
}
if (grid[row][col] == checkRepeat(size,grid,row,col) || grid[row][col] == holder){
backtrack = 1; //if no valid number was found in the above
grid[row][col] = 0;
}
holder = 0;
}
}
So I may have gone a little overboard on the solution but I thought it was a good challenge for me. The basic idea is that fill(row, col) is a recursive function. First it checks the stopping conditions: if the filled-out part of the grid is not valid (a number is repeated in a row or column) it will return false. It will also return false if there's an attempt to fill outside the grid's size.
If neither stopping condition is met, it will try a value for the grid element and attempt to "fill the rest of the grid" (aka call the fn recursively). It will do those things as long as the "fill rest" operation fails and it hasn't tried all valid values. If it has tried all the valid values and the "fill rest" operation still fails, it resets the value to 0. Finally it returns whether the "fill rest" operation failed or succeeded.
#include <vector>
#include <iostream>
#include <cstdlib>
#include <numeric>
#include <time.h>
#include <string>
#include <sstream>
using std::vector;
// helper for std::accumulate
bool logical_and(bool x, bool y) {
return x & y;
}
class Grid {
public:
typedef int ElementType;
typedef vector< vector<ElementType> > GridElements;
Grid(const int linesize) :
linesize_(linesize)
{
srand(time(NULL));
// resizes to linesize_ rows & columns, with initial values == 0
gridElements_.resize(linesize_, vector<ElementType>(linesize_, 0));
}
// use like this: cout << grid.to_s();
std::string to_s() const {
std::stringstream ss;
for (int row = 0; row < gridElements_.size(); row++) {
for (int col = 0; col < gridElements_[row].size(); col++) {
ss << gridElements_[row][col] << " ";
}
ss << std::endl;
}
ss << std::endl;
return ss.str();
}
// return true if there are no repeated numbers within filled elements in
// rows/columns, false otherwise
bool isValid() const {
// you would also need to write and call a checkSquare method if you're doing a sudoku puzzle
for (int i = 0; i < linesize_; i++) {
if (!isRowValid(i) || !isColValid(i)) {
return false;
}
}
return true;
}
// the recursive function that actually puts values in the grid elements
// max recursion depth (I think) is linesize_^2
bool fill(int row, int col) {
// stopping conditions
if (!isValid()) {
return false;
}
if ((row == linesize_) || (col == linesize_)) {
return true;
}
int nextCol = (col + 1) % linesize_;
int nextRow = row;
if (nextCol < col) {
nextRow++;
}
// keep a record of what numbers have been tried in this element
vector<bool> attemptedNumbers(linesize_ + 1, false);
attemptedNumbers[0] = true;
// We will continue choosing values for gridElements_[row][col]
// as long as we haven't tried all the valid numbers, and as long as
// the rest of the grid is not valid with this choice
int value = 0;
bool triedAllNumbers = false;
bool restOfGridValid = false;
while (!triedAllNumbers && !restOfGridValid) {
while (attemptedNumbers[value]) {
value = rand() % linesize_ + 1;
}
attemptedNumbers[value] = true;
gridElements_[row][col] = value;
// uncomment this for debugging/intermediate grids
//std::cout << to_s();
// triedAllNumbers == true if all the numbers in [1, linesize_] have been tried
triedAllNumbers = std::accumulate(attemptedNumbers.begin(), attemptedNumbers.end(), true, logical_and);
restOfGridValid = fill(nextRow, nextCol);
}
if (triedAllNumbers && !restOfGridValid) {
// couldn't find a valid number for this location
gridElements_[row][col] = 0;
}
return restOfGridValid;
}
private:
// checks that a number is used only once in the row
// assumes that values in gridElements_ are in [1, linesize_]
// return false when the row contains repeated values, true otherwise
bool isRowValid(int row) const {
vector<bool> numPresent (linesize_ + 1, false);
for (int i = 0; i < linesize_; i++) {
int element = gridElements_[row][i];
if (element != 0) {
if (numPresent[element]) {
return false;
}
else {
numPresent[element] = true;
}
}
// don't do anything if element == 0
}
return true;
}
// checks that a number is used only once in the column
// assumes that values in gridElements_ are in [1, linesize_]
// return false when the column contains repeated values, true otherwise
bool isColValid(int col) const {
vector<bool> numPresent (linesize_ + 1, false);
for (int i = 0; i < linesize_; i++) {
int element = gridElements_[i][col];
if (element != 0) {
if (numPresent[element]) {
return false;
}
else {
numPresent[element] = true;
}
}
else {
// if element == 0, there isn't anything left to check, so just leave the loop
break;
}
}
return true;
}
// the size of each row/column
int linesize_;
// the 2d array
GridElements gridElements_;
};
int main(int argc, char** argv) {
// 6x6 grid
Grid grid(6);
// pretty sure this is mathematically guaranteed to always return true, assuming the algorithm is implemented correctly ;)
grid.fill(0, 0);
std::cout << grid.to_s();
}