diff --git a/CMakeLists.txt b/CMakeLists.txt index bfaeccdbe..8d0ed28c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ add_subdirectory(sorting) add_subdirectory(geometry) add_subdirectory(graphics) add_subdirectory(probability) +add_subdirectory(backtracking) add_subdirectory(data_structures) add_subdirectory(machine_learning) add_subdirectory(numerical_methods) diff --git a/backtracking/CMakeLists.txt b/backtracking/CMakeLists.txt new file mode 100644 index 000000000..f636edae5 --- /dev/null +++ b/backtracking/CMakeLists.txt @@ -0,0 +1,18 @@ +# If necessary, use the RELATIVE flag, otherwise each source file may be listed +# with full pathname. RELATIVE may makes it easier to extract an executable name +# automatically. +file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp ) +# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c ) +# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES) +foreach( testsourcefile ${APP_SOURCES} ) + # I used a simple string replace, to cut off .cpp. + string( REPLACE ".cpp" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX) + if(OpenMP_CXX_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_CXX) + endif() + install(TARGETS ${testname} DESTINATION "bin/backtracking") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/backtracking/graph_coloring.cpp b/backtracking/graph_coloring.cpp index 19a983019..f2ac572c5 100644 --- a/backtracking/graph_coloring.cpp +++ b/backtracking/graph_coloring.cpp @@ -1,72 +1,117 @@ -#include +/** + * @file + * @brief prints the assigned colors + * using [Graph Coloring](https://en.wikipedia.org/wiki/Graph_coloring) algorithm + * + * @details + * In graph theory, graph coloring is a special case of graph labeling; + * it is an assignment of labels traditionally called "colors" to elements of a graph subject to certain constraints. + * In its simplest form, it is a way of coloring the vertices of a graph such that no two adjacent vertices are of the same color; + * this is called a vertex coloring. Similarly, an edge coloring assigns + * a color to each edge so that no two adjacent edges are of the same color, + * and a face coloring of a planar graph assigns a color to each face or + * region so that no two faces that share a boundary have the same color. + * + * @author [Anup Kumar Panwar](https://github.com/AnupKumarPanwar) + * @author [David Leal](https://github.com/Panquesito7) + */ +#include +#include +#include -// Number of vertices in the graph -#define V 4 - -void printSolution(int color[]); - -/* A utility function to check if the current color assignment - is safe for vertex v */ -bool isSafe(int v, bool graph[V][V], int color[], int c) { - for (int i = 0; i < V; i++) - if (graph[v][i] && c == color[i]) - return false; - return true; -} - -/* A recursive utility function to solve m coloring problem */ -void graphColoring(bool graph[V][V], int m, int color[], int v) { - /* base case: If all vertices are assigned a color then - return true */ - if (v == V) { - printSolution(color); - return; +/** + * @namespace + * @brief Backtracking algorithms + */ +namespace backtracking { + /** A utility function to print solution + * @tparam V number of vertices in the graph + * @param color array of colors assigned to the nodes + */ + template + void printSolution(const std::array & color) { + std::cout << "Following are the assigned colors\n"; + for (auto &col : color) { + std::cout << col; + } + std::cout << "\n"; } - /* Consider this vertex v and try different colors */ - for (int c = 1; c <= m; c++) { - /* Check if assignment of color c to v is fine*/ - if (isSafe(v, graph, color, c)) { - color[v] = c; + /** A utility function to check if the current color assignment is safe for + * vertex v + * @tparam V number of vertices in the graph + * @param v index of graph vertex to check + * @param graph matrix of graph nonnectivity + * @param color vector of colors assigned to the graph nodes/vertices + * @param c color value to check for the node `v` + * @returns `true` if the color is safe to be assigned to the node + * @returns `false` if the color is not safe to be assigned to the node + */ + template + bool isSafe(int v, const std::array, V>& graph, const std::array & color, int c) { + for (int i = 0; i < V; i++) { + if (graph[v][i] && c == color[i]) { + return false; + } + } + return true; + } - /* recur to assign colors to rest of the vertices */ - graphColoring(graph, m, color, v + 1); + /** A recursive utility function to solve m coloring problem + * @tparam V number of vertices in the graph + * @param graph matrix of graph nonnectivity + * @param m number of colors + * @param [in,out] color description // used in,out to notify in documentation + * that this parameter gets modified by the function + * @param v index of graph vertex to check + */ + template + void graphColoring(const std::array, V>& graph, int m, std::array color, int v) { + // base case: + // If all vertices are assigned a color then return true + if (v == V) { + backtracking::printSolution(color); + return; + } - /* If assigning color c doesn't lead to a solution - then remove it */ - color[v] = 0; + // Consider this vertex v and try different colors + for (int c = 1; c <= m; c++) { + // Check if assignment of color c to v is fine + if (backtracking::isSafe(v, graph, color, c)) { + color[v] = c; + + // recur to assign colors to rest of the vertices + backtracking::graphColoring(graph, m, color, v + 1); + + // If assigning color c doesn't lead to a solution then remove it + color[v] = 0; + } } } -} +} // namespace backtracking -/* A utility function to print solution */ -void printSolution(int color[]) { - printf(" Following are the assigned colors \n"); - for (int i = 0; i < V; i++) printf(" %d ", color[i]); - printf("\n"); -} - -// driver program to test above function +/** + * Main function + */ int main() { - /* Create following graph and test whether it is 3 colorable - (3)---(2) - | / | - | / | - | / | - (0)---(1) - */ - bool graph[V][V] = { - {0, 1, 1, 1}, - {1, 0, 1, 0}, - {1, 1, 0, 1}, - {1, 0, 1, 0}, + // Create following graph and test whether it is 3 colorable + // (3)---(2) + // | / | + // | / | + // | / | + // (0)---(1) + + const int V = 4; // number of vertices in the graph + std::array , V> graph = { + std::array ({0, 1, 1, 1}), + std::array ({1, 0, 1, 0}), + std::array ({1, 1, 0, 1}), + std::array ({1, 0, 1, 0}) }; + int m = 3; // Number of colors + std::array color{}; - int color[V]; - - for (int i = 0; i < V; i++) color[i] = 0; - - graphColoring(graph, m, color, 0); + backtracking::graphColoring(graph, m, color, 0); return 0; } diff --git a/backtracking/knight_tour.cpp b/backtracking/knight_tour.cpp index c97523be7..88883ee07 100644 --- a/backtracking/knight_tour.cpp +++ b/backtracking/knight_tour.cpp @@ -1,60 +1,105 @@ +/** + * @file + * @brief [Knight's tour](https://en.wikipedia.org/wiki/Knight%27s_tour) algorithm + * + * @details + * A knight's tour is a sequence of moves of a knight on a chessboard + * such that the knight visits every square only once. If the knight + * ends on a square that is one knight's move from the beginning + * square (so that it could tour the board again immediately, following + * the same path, the tour is closed; otherwise, it is open. + * + * @author [Nikhil Arora](https://github.com/nikhilarora068) + * @author [David Leal](https://github.com/Panquesito7) + */ #include -#define n 8 +#include /** -A knight's tour is a sequence of moves of a knight on a chessboard -such that the knight visits every square only once. If the knight -ends on a square that is one knight's move from the beginning -square (so that it could tour the board again immediately, following -the same path), the tour is closed; otherwise, it is open. -**/ - -using std::cin; -using std::cout; - -bool issafe(int x, int y, int sol[n][n]) { - return (x < n && x >= 0 && y < n && y >= 0 && sol[x][y] == -1); -} -bool solve(int x, int y, int mov, int sol[n][n], int xmov[n], int ymov[n]) { - int k, xnext, ynext; - - if (mov == n * n) - return true; - - for (k = 0; k < 8; k++) { - xnext = x + xmov[k]; - ynext = y + ymov[k]; - - if (issafe(xnext, ynext, sol)) { - sol[xnext][ynext] = mov; - - if (solve(xnext, ynext, mov + 1, sol, xmov, ymov) == true) - return true; - else - sol[xnext][ynext] = -1; - } + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { + /** + * A utility function to check if i,j are valid indexes for N*N chessboard + * @tparam V number of vertices in array + * @param x current index in rows + * @param y current index in columns + * @param sol matrix where numbers are saved + * @returns `true` if .... + * @returns `false` if .... + */ + template + bool issafe(int x, int y, const std::array , V>& sol) { + return (x < V && x >= 0 && y < V && y >= 0 && sol[x][y] == -1); } - return false; -} + + /** + * Knight's tour algorithm + * @tparam V number of vertices in array + * @param x current index in rows + * @param y current index in columns + * @param mov movement to be done + * @param sol matrix where numbers are saved + * @param xmov next move of knight (x coordinate) + * @param ymov next move of knight (y coordinate) + * @returns `true` if solution exists + * @returns `false` if solution does not exist + */ + template + bool solve(int x, int y, int mov, std::array , V> &sol, + const std::array &xmov, std::array &ymov) { + int k, xnext, ynext; + + if (mov == V * V) { + return true; + } + + for (k = 0; k < V; k++) { + xnext = x + xmov[k]; + ynext = y + ymov[k]; + + if (backtracking::issafe(xnext, ynext, sol)) { + sol[xnext][ynext] = mov; + + if (backtracking::solve(xnext, ynext, mov + 1, sol, xmov, ymov) == true) { + return true; + } + else { + sol[xnext][ynext] = -1; + } + } + } + return false; + } +} // namespace backtracking + +/** + * Main function + */ int main() { - // initialize(); + const int n = 8; + std::array , n> sol = { 0 }; - int sol[n][n]; int i, j; - for (i = 0; i < n; i++) - for (j = 0; j < n; j++) sol[i][j] = -1; + for (i = 0; i < n; i++) { + for (j = 0; j < n; j++) { sol[i][j] = -1; } + } + + std::array xmov = { 2, 1, -1, -2, -2, -1, 1, 2 }; + std::array ymov = { 1, 2, 2, 1, -1, -2, -2, -1 }; - int xmov[8] = {2, 1, -1, -2, -2, -1, 1, 2}; - int ymov[8] = {1, 2, 2, 1, -1, -2, -2, -1}; sol[0][0] = 0; - bool flag = solve(0, 0, 1, sol, xmov, ymov); - if (flag == false) - cout << "solution doesnot exist \n"; + bool flag = backtracking::solve(0, 0, 1, sol, xmov, ymov); + if (flag == false) { + std::cout << "Error: Solution does not exist\n"; + } else { for (i = 0; i < n; i++) { - for (j = 0; j < n; j++) cout << sol[i][j] << " "; - cout << "\n"; + for (j = 0; j < n; j++) { std::cout << sol[i][j] << " "; } + std::cout << "\n"; } } + return 0; } diff --git a/backtracking/minimax.cpp b/backtracking/minimax.cpp index 4e46a5fb2..c39018805 100644 --- a/backtracking/minimax.cpp +++ b/backtracking/minimax.cpp @@ -1,27 +1,61 @@ +/** + * @file + * @brief returns which is the longest/shortest number + * using [minimax](https://en.wikipedia.org/wiki/Minimax) algorithm + * + * @details + * Minimax (sometimes MinMax, MM or saddle point) is a decision rule used in + * artificial intelligence, decision theory, game theory, statistics, + * and philosophy for minimizing the possible loss for a worst case (maximum loss) scenario. + * When dealing with gains, it is referred to as "maximin"—to maximize the minimum gain. + * Originally formulated for two-player zero-sum game theory, covering both the cases where players take + * alternate moves and those where they make simultaneous moves, it has also been extended to more + * complex games and to general decision-making in the presence of uncertainty. + * + * @author [Gleison Batista](https://github.com/gleisonbs) + * @author [David Leal](https://github.com/Panquesito7) + */ +#include #include #include -#include +#include -using std::cout; -using std::endl; -using std::max; -using std::min; -using std::vector; - -int minimax(int depth, int node_index, bool is_max, vector scores, - int height) { - if (depth == height) +/** + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { +/** + * Check which number is the maximum/minimum in the array + * @param depth current depth in game tree + * @param node_index current index in array + * @param is_max if current index is the longest number + * @param scores saved numbers in array + * @param height maximum height for game tree + * @return maximum or minimum number + */ +template +int minimax(int depth, int node_index, bool is_max, + const std::array &scores, double height) { + if (depth == height) { return scores[node_index]; + } int v1 = minimax(depth + 1, node_index * 2, !is_max, scores, height); int v2 = minimax(depth + 1, node_index * 2 + 1, !is_max, scores, height); - return is_max ? max(v1, v2) : min(v1, v2); + return is_max ? std::max(v1, v2) : std::min(v1, v2); } +} // namespace backtracking +/** + * Main function + */ int main() { - vector scores = {90, 23, 6, 33, 21, 65, 123, 34423}; - int height = log2(scores.size()); + std::array scores = {90, 23, 6, 33, 21, 65, 123, 34423}; + double height = log2(scores.size()); - cout << "Optimal value: " << minimax(0, 0, true, scores, height) << endl; + std::cout << "Optimal value: " << backtracking::minimax(0, 0, true, scores, height) + << std::endl; + return 0; } diff --git a/backtracking/sudoku_solve.cpp b/backtracking/sudoku_solve.cpp index b712b6ec7..57c6b5274 100644 --- a/backtracking/sudoku_solve.cpp +++ b/backtracking/sudoku_solve.cpp @@ -1,91 +1,150 @@ +/** + * @file + * @brief [Sudoku Solver](https://en.wikipedia.org/wiki/Sudoku) algorithm. + * + * @details + * Sudoku (数独, sūdoku, digit-single) (/suːˈdoʊkuː/, /-ˈdɒk-/, /sə-/, originally called + * Number Place) is a logic-based, combinatorial number-placement puzzle. + * In classic sudoku, the objective is to fill a 9×9 grid with digits so that each column, + * each row, and each of the nine 3×3 subgrids that compose the grid (also called "boxes", "blocks", or "regions") + * contain all of the digits from 1 to 9. The puzzle setter provides a + * partially completed grid, which for a well-posed puzzle has a single solution. + * + * @author [DarthCoder3200](https://github.com/DarthCoder3200) + * @author [David Leal](https://github.com/Panquesito7) + */ #include -using namespace std; -/// N=9; -int n = 9; +#include -bool isPossible(int mat[][9], int i, int j, int no) { - /// Row or col nahin hona chahiye - for (int x = 0; x < n; x++) { - if (mat[x][j] == no || mat[i][x] == no) { - return false; - } - } - - /// Subgrid mein nahi hona chahiye - int sx = (i / 3) * 3; - int sy = (j / 3) * 3; - - for (int x = sx; x < sx + 3; x++) { - for (int y = sy; y < sy + 3; y++) { - if (mat[x][y] == no) { +/** + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { + /** + * Checks if it's possible to place a 'no' + * @tparam V number of vertices in the array + * @param mat matrix where numbers are saved + * @param i current index in rows + * @param j current index in columns + * @param no number to be added in matrix + * @param n number of times loop will run + * @returns `true` if 'mat' is different from 'no' + * @returns `false` if 'mat' equals to 'no' + */ + template + bool isPossible(const std::array , V> &mat, int i, int j, int no, int n) { + /// Row or col nahin hona chahiye + for (int x = 0; x < n; x++) { + if (mat[x][j] == no || mat[i][x] == no) { return false; } } - } - return true; -} -void printMat(int mat[][9]) { - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - cout << mat[i][j] << " "; - if ((j + 1) % 3 == 0) { - cout << '\t'; + /// Subgrid mein nahi hona chahiye + int sx = (i / 3) * 3; + int sy = (j / 3) * 3; + + for (int x = sx; x < sx + 3; x++) { + for (int y = sy; y < sy + 3; y++) { + if (mat[x][y] == no) { + return false; + } } } - if ((i + 1) % 3 == 0) { - cout << endl; - } - cout << endl; - } -} -bool solveSudoku(int mat[][9], int i, int j) { - /// Base Case - if (i == 9) { - /// Solve kr chuke hain for 9 rows already - printMat(mat); return true; } - - /// Crossed the last Cell in the row - if (j == 9) { - return solveSudoku(mat, i + 1, 0); - } - - /// Blue Cell - Skip - if (mat[i][j] != 0) { - return solveSudoku(mat, i, j + 1); - } - /// White Cell - /// Try to place every possible no - for (int no = 1; no <= 9; no++) { - if (isPossible(mat, i, j, no)) { - /// Place the no - assuming solution aa jayega - mat[i][j] = no; - bool aageKiSolveHui = solveSudoku(mat, i, j + 1); - if (aageKiSolveHui) { - return true; + /** + * Utility function to print matrix + * @tparam V number of vertices in array + * @param mat matrix where numbers are saved + * @param n number of times loop will run + * @return void + */ + template + void printMat(const std::array , V> &mat, int n) { + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + std::cout << mat[i][j] << " "; + if ((j + 1) % 3 == 0) { + std::cout << '\t'; + } } - /// Nahin solve hui - /// loop will place the next no. + if ((i + 1) % 3 == 0) { + std::cout << std::endl; + } + std::cout << std::endl; } } - /// Sare no try kr liey, kisi se bhi solve nahi hui - mat[i][j] = 0; - return false; -} + /** + * Sudoku algorithm + * @tparam V number of vertices in array + * @param mat matrix where numbers are saved + * @param i current index in rows + * @param j current index in columns + * @returns `true` if 'no' was placed + * @returns `false` if 'no' was not placed + */ + template + bool solveSudoku(std::array , V> &mat, int i, int j) { + /// Base Case + if (i == 9) { + /// Solve kr chuke hain for 9 rows already + backtracking::printMat(mat, 9); + return true; + } + + /// Crossed the last Cell in the row + if (j == 9) { + return backtracking::solveSudoku(mat, i + 1, 0); + } + + /// Blue Cell - Skip + if (mat[i][j] != 0) { + return backtracking::solveSudoku(mat, i, j + 1); + } + /// White Cell + /// Try to place every possible no + for (int no = 1; no <= 9; no++) { + if (backtracking::isPossible(mat, i, j, no, 9)) { + /// Place the no - assuming solution aa jayega + mat[i][j] = no; + bool aageKiSolveHui = backtracking::solveSudoku(mat, i, j + 1); + if (aageKiSolveHui) { + return true; + } + /// Nahin solve hui + /// loop will place the next no. + } + } + /// Sare no try kr liey, kisi se bhi solve nahi hui + mat[i][j] = 0; + return false; + } +} // namespace backtracking + +/** + * Main function + */ int main() { - int mat[9][9] = {{5, 3, 0, 0, 7, 0, 0, 0, 0}, {6, 0, 0, 1, 9, 5, 0, 0, 0}, - {0, 9, 8, 0, 0, 0, 0, 6, 0}, {8, 0, 0, 0, 6, 0, 0, 0, 3}, - {4, 0, 0, 8, 0, 3, 0, 0, 1}, {7, 0, 0, 0, 2, 0, 0, 0, 6}, - {0, 6, 0, 0, 0, 0, 2, 8, 0}, {0, 0, 0, 4, 1, 9, 0, 0, 5}, - {0, 0, 0, 0, 8, 0, 0, 7, 9}}; + const int V = 9; + std::array , V> mat = { + std::array {5, 3, 0, 0, 7, 0, 0, 0, 0}, + std::array {6, 0, 0, 1, 9, 5, 0, 0, 0}, + std::array {0, 9, 8, 0, 0, 0, 0, 6, 0}, + std::array {8, 0, 0, 0, 6, 0, 0, 0, 3}, + std::array {4, 0, 0, 8, 0, 3, 0, 0, 1}, + std::array {7, 0, 0, 0, 2, 0, 0, 0, 6}, + std::array {0, 6, 0, 0, 0, 0, 2, 8, 0}, + std::array {0, 0, 0, 4, 1, 9, 0, 0, 5}, + std::array {0, 0, 0, 0, 8, 0, 0, 7, 9} + }; - printMat(mat); - cout << "Solution " << endl; - solveSudoku(mat, 0, 0); + backtracking::printMat(mat, 9); + std::cout << "Solution " << std::endl; + backtracking::solveSudoku(mat, 0, 0); return 0; }