diff --git a/DIRECTORY.md b/DIRECTORY.md index 00757255a..2c919e0da 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -2,6 +2,7 @@ ## Backtracking * [Graph Coloring](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/graph_coloring.cpp) * [Knight Tour](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/knight_tour.cpp) + * [Magic Sequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/magic_sequence.cpp) * [Minimax](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/minimax.cpp) * [N Queens](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/n_queens.cpp) * [N Queens All Solution Optimised](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/n_queens_all_solution_optimised.cpp) diff --git a/backtracking/magic_sequence.cpp b/backtracking/magic_sequence.cpp new file mode 100644 index 000000000..13a260dc9 --- /dev/null +++ b/backtracking/magic_sequence.cpp @@ -0,0 +1,135 @@ +/* + * @brief [Magic sequence](https://www.csplib.org/Problems/prob019/) + * implementation + * + * @details Solve the magic sequence problem with backtracking + * + * "A magic sequence of length $n$ is a sequence of integers $x_0 + * \ldots x_{n-1}$ between $0$ and $n-1$, such that for all $i$ + * in $0$ to $n-1$, the number $i$ occurs exactly $x_i$ times in + * the sequence. For instance, $6,2,1,0,0,0,1,0,0,0$ is a magic + * sequence since $0$ occurs $6$ times in it, $1$ occurs twice, etc." + * Quote taken from the [CSPLib](https://www.csplib.org/Problems/prob019/) + * website + * + * @author [Jxtopher](https://github.com/Jxtopher) + */ + +#include /// for std::count +#include /// for assert +#include /// for IO operations +#include /// for std::list +#include /// for std::accumulate +#include /// for std::vector + +/** + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { +/** + * @namespace magic_sequence + * @brief Functions for the [Magic + * sequence](https://www.csplib.org/Problems/prob019/) implementation + */ +namespace magic_sequence { +using sequence_t = + std::vector; ///< Definition of the sequence type +/** + * @brief Print the magic sequence + * @param s working memory for the sequence + */ +void print(const sequence_t& s) { + for (const auto& item : s) std::cout << item << " "; + std::cout << std::endl; +} + +/** + * @brief Check if the sequence is magic + * @param s working memory for the sequence + * @returns true if it's a magic sequence + * @returns false if it's NOT a magic sequence + */ +bool is_magic(const sequence_t& s) { + for (unsigned int i = 0; i < s.size(); i++) { + if (std::count(s.cbegin(), s.cend(), i) != s[i]) { + return false; + } + } + return true; +} + +/** + * @brief Sub-solutions filtering + * @param s working memory for the sequence + * @param depth current depth in tree + * @returns true if the sub-solution is valid + * @returns false if the sub-solution is NOT valid + */ +bool filtering(const sequence_t& s, unsigned int depth) { + return std::accumulate(s.cbegin(), s.cbegin() + depth, + static_cast(0)) <= s.size(); +} + +/** + * @brief Solve the Magic Sequence problem + * @param s working memory for the sequence + * @param ret list of the valid magic sequences + * @param depth current depth in the tree + */ +void solve(sequence_t* s, std::list* ret, unsigned int depth = 0) { + if (depth == s->size()) { + if (is_magic(*s)) { + ret->push_back(*s); + } + } else { + for (unsigned int i = 0; i < s->size(); i++) { + (*s)[depth] = i; + if (filtering(*s, depth + 1)) { + solve(s, ret, depth + 1); + } + } + } +} + +} // namespace magic_sequence +} // namespace backtracking + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // test a valid magic sequence + backtracking::magic_sequence::sequence_t s_magic = {6, 2, 1, 0, 0, + 0, 1, 0, 0, 0}; + assert(backtracking::magic_sequence::is_magic(s_magic)); + + // test a non-valid magic sequence + backtracking::magic_sequence::sequence_t s_not_magic = {5, 2, 1, 0, 0, + 0, 1, 0, 0, 0}; + assert(!backtracking::magic_sequence::is_magic(s_not_magic)); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + + // solve magic sequences of size 2 to 11 and print the solutions + for (unsigned int i = 2; i < 12; i++) { + std::cout << "Solution for n = " << i << std::endl; + // valid magic sequence list + std::list list_of_solutions; + // initialization of a sequence + backtracking::magic_sequence::sequence_t s1(i, i); + // launch of solving the problem + backtracking::magic_sequence::solve(&s1, &list_of_solutions); + // print solutions + for (const auto& item : list_of_solutions) { + backtracking::magic_sequence::print(item); + } + } +}