From 24653d91944c9020dc0003e120578e792a77a940 Mon Sep 17 00:00:00 2001 From: Filip Hlasek Date: Fri, 7 Aug 2020 09:40:04 -0700 Subject: [PATCH 1/5] fix: linter warnings for bridge finding algorithm. (#991) * Fix linter warnings for bridge finding algorithm. * Comment main function. --- .../bridge_finding_with_tarjan_algorithm.cpp | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/graph/bridge_finding_with_tarjan_algorithm.cpp b/graph/bridge_finding_with_tarjan_algorithm.cpp index eec176af5..a9f76c033 100644 --- a/graph/bridge_finding_with_tarjan_algorithm.cpp +++ b/graph/bridge_finding_with_tarjan_algorithm.cpp @@ -7,15 +7,13 @@ #include // for min & max #include // for cout #include // for std::vector -using std::cout; -using std::min; -using std::vector; + class Solution { - vector> graph; - vector in_time, out_time; - int timer; - vector> bridge; - vector visited; + std::vector> graph; + std::vector in_time, out_time; + int timer = 0; + std::vector> bridge; + std::vector visited; void dfs(int current_node, int parent) { visited.at(current_node) = true; in_time[current_node] = out_time[current_node] = timer++; @@ -29,13 +27,14 @@ class Solution { bridge.push_back({itr, current_node}); } } - out_time[current_node] = min(out_time[current_node], out_time[itr]); + out_time[current_node] = std::min(out_time[current_node], out_time[itr]); } } public: - vector> search_bridges(int n, - const vector>& connections) { + std::vector> search_bridges( + int n, + const std::vector>& connections) { timer = 0; graph.resize(n); in_time.assign(n, 0); @@ -49,10 +48,14 @@ class Solution { return bridge; } }; -int main(void) { + +/** + * Main function + */ +int main() { Solution s1; int number_of_node = 5; - vector> node; + std::vector> node; node.push_back({0, 1}); node.push_back({1, 3}); node.push_back({1, 2}); @@ -70,10 +73,10 @@ int main(void) { * I assumed that the graph is bi-directional and connected. * */ - vector> bridges = s1.search_bridges(number_of_node, node); - cout << bridges.size() << " bridges found!\n"; + std::vector> bridges = s1.search_bridges(number_of_node, node); + std::cout << bridges.size() << " bridges found!\n"; for (auto& itr : bridges) { - cout << itr[0] << " --> " << itr[1] << '\n'; + std::cout << itr[0] << " --> " << itr[1] << '\n'; } return 0; } From 426a12da58c8bd1ac67e1b84251fea9912858991 Mon Sep 17 00:00:00 2001 From: Filip Hlasek Date: Fri, 7 Aug 2020 09:40:44 -0700 Subject: [PATCH 2/5] fix: linter warnings for topological_sort_by_kahns_algo (#993) --- graph/topological_sort_by_kahns_algo.cpp | 41 ++++++++++++------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/graph/topological_sort_by_kahns_algo.cpp b/graph/topological_sort_by_kahns_algo.cpp index 57ee01b23..c29c0fc2d 100644 --- a/graph/topological_sort_by_kahns_algo.cpp +++ b/graph/topological_sort_by_kahns_algo.cpp @@ -1,19 +1,20 @@ -#include -#include +#include +#include #include #include #include -int *topoSortKahn(int N, std::vector adj[]); +std::vector topoSortKahn(int N, const std::vector< std::vector > &adj); int main() { - int nodes, edges; + int nodes = 0, edges = 0; std::cin >> edges >> nodes; - if (edges == 0 || nodes == 0) + if (edges == 0 || nodes == 0) { return 0; - int u, v; + } + int u = 0, v = 0; - std::vector graph[nodes]; + std::vector< std::vector > graph(nodes); // create graph // example // 6 6 @@ -24,19 +25,19 @@ int main() { graph[u].push_back(v); } - int *topo = topoSortKahn(nodes, graph); + std::vector topo = topoSortKahn(nodes, graph); // topologically sorted nodes for (int i = 0; i < nodes; i++) { std::cout << topo[i] << " "; } } -int *topoSortKahn(int V, std::vector adj[]) { +std::vector topoSortKahn(int V, const std::vector< std::vector > &adj) { std::vector vis(V + 1, false); std::vector deg(V + 1, 0); for (int i = 0; i < V; i++) { - for (int j = 0; j < adj[i].size(); j++) { - deg[adj[i][j]]++; + for (int j : adj[i]) { + deg[j]++; } } std::queue q; @@ -46,20 +47,18 @@ int *topoSortKahn(int V, std::vector adj[]) { vis[i] = true; } } - int *arr = new int[V + 1]; - memset(arr, 0, V + 1); + std::vector arr(V + 1, 0); int count = 0; while (!q.empty()) { int cur = q.front(); q.pop(); - arr[count] = cur; - count++; - for (int i = 0; i < adj[cur].size(); i++) { - if (!vis[adj[cur][i]]) { - deg[adj[cur][i]]--; - if (deg[adj[cur][i]] == 0) { - q.push(adj[cur][i]); - vis[adj[cur][i]] = true; + arr[count++] = cur; + for (int i : adj[cur]) { + if (!vis[i]) { + deg[i]--; + if (deg[i] == 0) { + q.push(i); + vis[i] = true; } } } From 418e876dfefae82088849b5ed7b5a8ae57862900 Mon Sep 17 00:00:00 2001 From: Filip Hlasek Date: Fri, 7 Aug 2020 09:49:12 -0700 Subject: [PATCH 3/5] Fix linter warnings for connected_components_with_dsu. (#992) --- graph/connected_components_with_dsu.cpp | 28 +++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/graph/connected_components_with_dsu.cpp b/graph/connected_components_with_dsu.cpp index aa03bef8f..50d0c4242 100644 --- a/graph/connected_components_with_dsu.cpp +++ b/graph/connected_components_with_dsu.cpp @@ -2,19 +2,20 @@ #include #include -int N; // denotes number of nodes; +int number_of_nodes; // denotes number of nodes; std::vector parent; -std::vector siz; +std::vector connected_set_size; void make_set() { // function the initialize every node as it's own parent - for (int i = 1; i <= N; i++) { + for (int i = 1; i <= number_of_nodes; i++) { parent[i] = i; - siz[i] = 1; + connected_set_size[i] = 1; } } // To find the component where following node belongs to int find_set(int v) { - if (v == parent[v]) + if (v == parent[v]) { return v; + } return parent[v] = find_set(parent[v]); } @@ -22,30 +23,31 @@ void union_sets(int a, int b) { // To join 2 components to belong to one a = find_set(a); b = find_set(b); if (a != b) { - if (siz[a] < siz[b]) + if (connected_set_size[a] < connected_set_size[b]) { std::swap(a, b); + } parent[b] = a; - siz[a] += siz[b]; + connected_set_size[a] += connected_set_size[b]; } } int no_of_connected_components() { // To find total no of connected components std::set temp; // temp set to count number of connected components - for (int i = 1; i <= N; i++) temp.insert(find_set(i)); + for (int i = 1; i <= number_of_nodes; i++) temp.insert(find_set(i)); return temp.size(); } // All critical/corner cases have been taken care of. // Input your required values: (not hardcoded) int main() { - std::cin >> N; - parent.resize(N + 1); - siz.resize(N + 1); + std::cin >> number_of_nodes; + parent.resize(number_of_nodes + 1); + connected_set_size.resize(number_of_nodes + 1); make_set(); - int edges; + int edges = 0; std::cin >> edges; // no of edges in the graph while (edges--) { - int node_a, node_b; + int node_a = 0, node_b = 0; std::cin >> node_a >> node_b; union_sets(node_a, node_b); } From b36ce9a8c07aee28381a7e922aa1b68bf0d71f54 Mon Sep 17 00:00:00 2001 From: Filip Hlasek Date: Fri, 7 Aug 2020 09:52:44 -0700 Subject: [PATCH 4/5] fix: linter warnings for topological_sort. (#994) Approving for now to enable a PR that adds graph folder to the CI build system. --- graph/topological_sort.cpp | 49 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/graph/topological_sort.cpp b/graph/topological_sort.cpp index 9e6c8917b..3827b9bcf 100644 --- a/graph/topological_sort.cpp +++ b/graph/topological_sort.cpp @@ -1,47 +1,48 @@ #include #include #include -using namespace std; -int n, m; // For number of Vertices (V) and number of edges (E) -vector> G; -vector visited; -vector ans; +int number_of_vertices, number_of_edges; // For number of Vertices (V) and number of edges (E) +std::vector> graph; +std::vector visited; +std::vector topological_order; void dfs(int v) { visited[v] = true; - for (int u : G[v]) { - if (!visited[u]) + for (int u : graph[v]) { + if (!visited[u]) { dfs(u); + } } - ans.push_back(v); + topological_order.push_back(v); } void topological_sort() { - visited.assign(n, false); - ans.clear(); - for (int i = 0; i < n; ++i) { - if (!visited[i]) + visited.assign(number_of_vertices, false); + topological_order.clear(); + for (int i = 0; i < number_of_vertices; ++i) { + if (!visited[i]) { dfs(i); + } } - reverse(ans.begin(), ans.end()); + reverse(topological_order.begin(), topological_order.end()); } int main() { - cout << "Enter the number of vertices and the number of directed edges\n"; - cin >> n >> m; - int x, y; - G.resize(n, vector()); - for (int i = 0; i < n; ++i) { - cin >> x >> y; + std::cout << "Enter the number of vertices and the number of directed edges\n"; + std::cin >> number_of_vertices >> number_of_edges; + int x = 0, y = 0; + graph.resize(number_of_vertices, std::vector()); + for (int i = 0; i < number_of_edges; ++i) { + std::cin >> x >> y; x--, y--; // to convert 1-indexed to 0-indexed - G[x].push_back(y); + graph[x].push_back(y); } topological_sort(); - cout << "Topological Order : \n"; - for (int v : ans) { - cout << v + 1 + std::cout << "Topological Order : \n"; + for (int v : topological_order) { + std::cout << v + 1 << ' '; // converting zero based indexing back to one based. } - cout << '\n'; + std::cout << '\n'; return 0; } From 25b39a34fa674d3ef0d40a94d72a4e73c96f5bfe Mon Sep 17 00:00:00 2001 From: David Leal Date: Fri, 7 Aug 2020 13:35:59 -0500 Subject: [PATCH 5/5] [fix/docs]: Update backtracking folder (#916) * [fix/docs]: Update backtracking/graph_coloring.cpp * Add CMakeLists.txt in backtracking folder * Add backtracking to CMakeLists.txt * fix: Fix build issues * docs: Various documentation fixes * fix: minimax.cpp issues * fix: sudoku_solve.cpp fixes * formatting source-code for 8ffbbb35cecc5fb3dac33957e14e9da50cff9469 * make he code neat and clean without global variables * fix 2 stars in comment * fix MSVC errors by forcing template parameter in function calls Note: This is identical to passing it as a function parameter, and may not be helpful * Update minimax.cpp * docs: minimax.cpp improvements * docs: Add Wikipedia link in minimax.cpp * fix: minimax.cpp vector fix * docs: fix Wikipedia link in minimax.cpp * docs: fix return statement in minimax.cpp * fix: sudoku_solve.cpp fixes * fix: more sudoku_solve.cpp fixes * fix: sudoku_solve.cpp fixes * fix: sudoku_solve.cpp * formatting source-code for 13b5b9b829eecc242746f6f00d54c35dad6c026a * docs: update graph_coloring.cpp description * fix: use array instead of vector (minimax.cpp) * feat: add namespace (minimax.cpp) * docs: update namespace description (graph_coloring.cpp) * fix: graph_coloring.cpp * fix: sudoku_solve.cpp fixes * fix: graph_coloring.cpp * fix: minimax.cpp * fix: more sudoku_solve.cpp fixes * fix: more graph_coloring.cpp fixes * fix: graph_coloring.cpp fixes * fix: sudoku_solve.cpp fixes * fix: minimax.cpp * fix: sudoku_solve.cpp fixes * fix: too few template arguments (std::array) * fix: too few template arguments (std::array, minimax.cpp) * fix: narrowing conversion from double to int (minimax.cpp) * fix: excess elements in struct initializer (graph_coloring.cpp) * fix: no matching function (graph_coloring.cpp) * fix: graph_coloring.cpp issues/errors * fix: knight_tour.cpp issues/errors * fix: sudoku_solve.cpp issues/errors * [fix/docs]: Various fixes in graph_coloring.cpp * fix: More graph_coloring.cpp fixes * docs: Add initial comment block (sudoku_solve.cpp) * fix: Add return statement (knight_tour.cpp) * fix: array fixes (graph_coloring.cpp) * docs: documentation improvements (sudoku_solve.cpp) * docs: documentation improvements (knight_tour.cpp) * docs: documentation improvements (sudoku_solve.cpp) * docs: documentation improvements (graph_coloring.cpp) * docs: Documentation improvements (graph_coloring.cpp) Thanks, @kvedala! * docs: Documentation improvements (sudoku_solve.cpp) * docs: Document function parameter (sudoku_solve.cpp) * docs: Documentation improvements (knight_tour.cpp) * docs: Add long description (graph_coloring.cpp) * docs: Add long description (minimax.cpp) * docs: Add long description (sudoku_solve.cpp) * docs: Documentation improvements (knight_tour.cpp) * docs: Documentation improvements (sudoku_solve.cpp) * docs: Documentation improvements (minimax.cpp) * docs: More documentation improvements (minimax.cpp) * docs: Documentation improvements (sudoku_solve.cpp) * fix: sudoku_solve.cpp improvements Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> --- CMakeLists.txt | 1 + backtracking/CMakeLists.txt | 18 +++ backtracking/graph_coloring.cpp | 161 ++++++++++++++++--------- backtracking/knight_tour.cpp | 135 ++++++++++++++------- backtracking/minimax.cpp | 62 +++++++--- backtracking/sudoku_solve.cpp | 201 +++++++++++++++++++++----------- 6 files changed, 390 insertions(+), 188 deletions(-) create mode 100644 backtracking/CMakeLists.txt 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; }